2 * Copyright (c) 2020 PANTHEON.tech, s.r.o. 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
9 package org.opendaylight.netconf.sal.rest.doc.model.builder;
11 import static org.opendaylight.netconf.sal.rest.doc.impl.DefinitionGenerator.INPUT;
12 import static org.opendaylight.netconf.sal.rest.doc.impl.DefinitionGenerator.INPUT_SUFFIX;
13 import static org.opendaylight.netconf.sal.rest.doc.impl.DefinitionGenerator.OUTPUT_SUFFIX;
15 import com.fasterxml.jackson.databind.JsonNode;
16 import com.fasterxml.jackson.databind.node.ArrayNode;
17 import com.fasterxml.jackson.databind.node.JsonNodeFactory;
18 import com.fasterxml.jackson.databind.node.ObjectNode;
19 import java.util.List;
20 import java.util.Optional;
21 import javax.ws.rs.HttpMethod;
22 import javax.ws.rs.core.MediaType;
23 import javax.ws.rs.core.Response;
24 import org.opendaylight.netconf.sal.rest.doc.impl.DefinitionNames;
25 import org.opendaylight.netconf.sal.rest.doc.util.JsonUtil;
26 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
27 import org.opendaylight.yangtools.yang.model.api.InputSchemaNode;
28 import org.opendaylight.yangtools.yang.model.api.OperationDefinition;
29 import org.opendaylight.yangtools.yang.model.api.OutputSchemaNode;
31 public final class OperationBuilder {
32 public static final String CONFIG = "_config";
33 public static final String CONFIG_QUERY_PARAM = "config";
34 public static final String CONTENT_KEY = "content";
35 public static final String COMPONENTS_PREFIX = "#/components/schemas/";
36 public static final String DESCRIPTION_KEY = "description";
37 public static final String IN_KEY = "in";
38 public static final String INPUT_KEY = "input";
39 public static final String NAME_KEY = "name";
40 public static final String NONCONFIG_QUERY_PARAM = "nonconfig";
41 public static final String PARAMETERS_KEY = "parameters";
42 public static final String POST_SUFFIX = "_post";
43 public static final String PROPERTIES_KEY = "properties";
44 public static final String REF_KEY = "$ref";
45 public static final String REQUEST_BODY_KEY = "requestBody";
46 public static final String RESPONSES_KEY = "responses";
47 public static final String SCHEMA_KEY = "schema";
48 public static final String SUMMARY_KEY = "summary";
49 public static final String SUMMARY_SEPARATOR = " - ";
50 public static final String TAGS_KEY = "tags";
51 public static final String TOP = "_TOP";
52 public static final String XML_KEY = "xml";
53 public static final String XML_SUFFIX = "_xml";
54 private static final String CONTENT = "content";
55 private static final ArrayNode CONSUMES_PUT_POST;
56 private static final String ENUM_KEY = "enum";
57 private static final List<String> MIME_TYPES = List.of(MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON);
58 private static final String OBJECT = "object";
59 private static final String REQUIRED_KEY = "required";
60 private static final String STRING = "string";
61 private static final String TYPE_KEY = "type";
62 private static final String QUERY = "query";
65 CONSUMES_PUT_POST = JsonNodeFactory.instance.arrayNode();
66 for (final String mimeType : MIME_TYPES) {
67 CONSUMES_PUT_POST.add(mimeType);
71 private OperationBuilder() {
75 public static ObjectNode buildPost(final String parentName, final String nodeName, final String discriminator,
76 final String moduleName, final Optional<String> deviceName, final String description,
77 final ArrayNode pathParams) {
78 final ObjectNode value = JsonNodeFactory.instance.objectNode();
79 value.put(DESCRIPTION_KEY, description);
80 value.put(SUMMARY_KEY, buildSummaryValue(HttpMethod.POST, moduleName, deviceName, nodeName));
81 value.set(TAGS_KEY, buildTagsValue(deviceName, moduleName));
82 final ArrayNode parameters = JsonUtil.copy(pathParams);
83 final ObjectNode ref = JsonNodeFactory.instance.objectNode();
84 final String cleanDefName = parentName + CONFIG + "_" + nodeName + POST_SUFFIX;
85 final String defName = cleanDefName + discriminator;
86 final String xmlDefName = cleanDefName + XML_SUFFIX + discriminator;
87 ref.put(REF_KEY, COMPONENTS_PREFIX + defName);
88 insertRequestBodyParameter(value, defName, xmlDefName, nodeName + CONFIG);
89 value.set(PARAMETERS_KEY, parameters);
91 final ObjectNode responses = JsonNodeFactory.instance.objectNode();
92 responses.set(String.valueOf(Response.Status.CREATED.getStatusCode()),
93 buildResponse(Response.Status.CREATED.getReasonPhrase(), Optional.empty()));
95 value.set(RESPONSES_KEY, responses);
99 public static ObjectNode buildGet(final DataSchemaNode node, final String moduleName,
100 final Optional<String> deviceName, final ArrayNode pathParams, final String defName,
101 final boolean isConfig) {
102 final ObjectNode value = JsonNodeFactory.instance.objectNode();
103 value.put(DESCRIPTION_KEY, node.getDescription().orElse(""));
104 value.put(SUMMARY_KEY, buildSummaryValue(HttpMethod.GET, moduleName, deviceName,
105 node.getQName().getLocalName()));
106 value.set(TAGS_KEY, buildTagsValue(deviceName, moduleName));
107 final ArrayNode parameters = JsonUtil.copy(pathParams);
109 addQueryParameters(parameters, isConfig);
111 value.set(PARAMETERS_KEY, parameters);
113 final ObjectNode responses = JsonNodeFactory.instance.objectNode();
114 final ObjectNode schema = JsonNodeFactory.instance.objectNode();
115 schema.put(REF_KEY, COMPONENTS_PREFIX + defName);
116 responses.set(String.valueOf(Response.Status.OK.getStatusCode()),
117 buildResponse(Response.Status.OK.getReasonPhrase(), Optional.of(schema)));
119 value.set(RESPONSES_KEY, responses);
123 private static void addQueryParameters(final ArrayNode parameters, final boolean isConfig) {
124 final ObjectNode contentParam = JsonNodeFactory.instance.objectNode();
125 final ArrayNode cases = JsonNodeFactory.instance.arrayNode();
126 cases.add(NONCONFIG_QUERY_PARAM);
128 cases.add(CONFIG_QUERY_PARAM);
130 contentParam.put(REQUIRED_KEY, true);
132 contentParam.put(IN_KEY, QUERY);
133 contentParam.put(NAME_KEY, CONTENT);
135 final ObjectNode typeParent = getTypeParentNode(contentParam);
136 typeParent.put(TYPE_KEY, STRING);
137 typeParent.set(ENUM_KEY, cases);
139 parameters.add(contentParam);
142 public static ObjectNode buildPut(final String parentName, final String nodeName, final String discriminator,
143 final String moduleName, final Optional<String> deviceName, final String description,
144 final ArrayNode pathParams) {
145 final ObjectNode value = JsonNodeFactory.instance.objectNode();
146 value.put(DESCRIPTION_KEY, description);
147 value.put(SUMMARY_KEY, buildSummaryValue(HttpMethod.PUT, moduleName, deviceName, nodeName));
148 value.set(TAGS_KEY, buildTagsValue(deviceName, moduleName));
149 final ArrayNode parameters = JsonUtil.copy(pathParams);
150 final String defName = parentName + CONFIG + "_" + nodeName + TOP;
151 final String xmlDefName = parentName + CONFIG + "_" + nodeName;
152 insertRequestBodyParameter(value, defName, xmlDefName, nodeName + CONFIG);
153 value.set(PARAMETERS_KEY, parameters);
155 final ObjectNode responses = JsonNodeFactory.instance.objectNode();
156 responses.set(String.valueOf(Response.Status.CREATED.getStatusCode()),
157 buildResponse(Response.Status.CREATED.getReasonPhrase(), Optional.empty()));
158 responses.set(String.valueOf(Response.Status.NO_CONTENT.getStatusCode()),
159 buildResponse("Updated", Optional.empty()));
161 value.set(RESPONSES_KEY, responses);
165 public static ObjectNode buildPatch(final String parentName, final String nodeName, final String moduleName,
166 final Optional<String> deviceName, final String description, final ArrayNode pathParams) {
167 final ObjectNode value = JsonNodeFactory.instance.objectNode();
168 value.put(DESCRIPTION_KEY, description);
169 value.put(SUMMARY_KEY, buildSummaryValue(HttpMethod.PATCH, moduleName, deviceName, nodeName));
170 value.set(TAGS_KEY, buildTagsValue(deviceName, moduleName));
171 final ArrayNode parameters = JsonUtil.copy(pathParams);
172 final String defName = parentName + CONFIG + "_" + nodeName + TOP;
173 final String xmlDefName = parentName + CONFIG + "_" + nodeName;
174 insertRequestBodyParameter(value, defName, xmlDefName, nodeName + CONFIG);
175 value.set(PARAMETERS_KEY, parameters);
177 final ObjectNode responses = JsonNodeFactory.instance.objectNode();
178 responses.set(String.valueOf(Response.Status.OK.getStatusCode()),
179 buildResponse(Response.Status.OK.getReasonPhrase(), Optional.empty()));
180 responses.set(String.valueOf(Response.Status.NO_CONTENT.getStatusCode()),
181 buildResponse("Updated", Optional.empty()));
183 value.set(RESPONSES_KEY, responses);
187 public static ObjectNode buildDelete(final DataSchemaNode node, final String moduleName,
188 final Optional<String> deviceName, final ArrayNode pathParams) {
189 final ObjectNode value = JsonNodeFactory.instance.objectNode();
190 value.put(SUMMARY_KEY, buildSummaryValue(HttpMethod.DELETE, moduleName, deviceName,
191 node.getQName().getLocalName()));
192 value.set(TAGS_KEY, buildTagsValue(deviceName, moduleName));
193 value.put(DESCRIPTION_KEY, node.getDescription().orElse(""));
194 final ArrayNode parameters = JsonUtil.copy(pathParams);
195 value.set(PARAMETERS_KEY, parameters);
197 final ObjectNode responses = JsonNodeFactory.instance.objectNode();
198 responses.set(String.valueOf(Response.Status.NO_CONTENT.getStatusCode()),
199 buildResponse("Deleted", Optional.empty()));
201 value.set(RESPONSES_KEY, responses);
205 public static ObjectNode buildPostOperation(final OperationDefinition operDef, final String moduleName,
206 final Optional<String> deviceName, final String parentName, final DefinitionNames definitionNames) {
207 final ObjectNode postOperation = JsonNodeFactory.instance.objectNode();
208 final ArrayNode parameters = JsonNodeFactory.instance.arrayNode();
209 final String operName = operDef.getQName().getLocalName();
210 final String inputName = operName + INPUT_SUFFIX;
212 final InputSchemaNode input = operDef.getInput();
213 final OutputSchemaNode output = operDef.getOutput();
214 if (!input.getChildNodes().isEmpty()) {
215 final String discriminator = definitionNames.getDiscriminator(input);
216 final String clearDefName = parentName + "_" + operName + INPUT_SUFFIX;
217 final String defName = clearDefName + discriminator;
218 final String defTopName = clearDefName + TOP + discriminator;
219 insertRequestBodyParameter(postOperation, defTopName, defName, inputName);
221 final ObjectNode payload = JsonNodeFactory.instance.objectNode();
222 final ObjectNode jsonSchema = JsonNodeFactory.instance.objectNode();
223 final ObjectNode properties = JsonNodeFactory.instance.objectNode();
224 final ObjectNode inputSchema = JsonNodeFactory.instance.objectNode();
225 inputSchema.put(TYPE_KEY, OBJECT);
226 properties.set(INPUT_KEY, inputSchema);
227 jsonSchema.put(TYPE_KEY, OBJECT);
228 jsonSchema.set(PROPERTIES_KEY, properties);
229 final ObjectNode content = JsonNodeFactory.instance.objectNode();
230 final ObjectNode jsonTypeValue = JsonNodeFactory.instance.objectNode();
231 jsonTypeValue.set(SCHEMA_KEY, jsonSchema);
232 content.set(MediaType.APPLICATION_JSON, jsonTypeValue);
234 final ObjectNode xmlSchema = JsonNodeFactory.instance.objectNode();
235 xmlSchema.put(TYPE_KEY, OBJECT);
236 final ObjectNode xml = JsonNodeFactory.instance.objectNode();
237 xml.put(NAME_KEY, INPUT);
238 xmlSchema.set(XML_KEY, xml);
239 final ObjectNode xmlTypeValue = JsonNodeFactory.instance.objectNode();
240 xmlTypeValue.set(SCHEMA_KEY, xmlSchema);
241 content.set(MediaType.APPLICATION_XML, xmlTypeValue);
243 payload.set(CONTENT_KEY, content);
244 payload.put(DESCRIPTION_KEY, inputName);
245 postOperation.set(REQUEST_BODY_KEY, payload);
247 postOperation.set(PARAMETERS_KEY, parameters);
248 final ObjectNode responses = JsonNodeFactory.instance.objectNode();
249 final String description = String.format("RPC %s success", operName);
251 if (!output.getChildNodes().isEmpty()) {
252 final ObjectNode schema = JsonNodeFactory.instance.objectNode();
253 final String defName = parentName + "_" + operName + OUTPUT_SUFFIX + TOP
254 + definitionNames.getDiscriminator(output);
255 schema.put(REF_KEY, COMPONENTS_PREFIX + defName);
256 responses.set(String.valueOf(Response.Status.OK.getStatusCode()), buildResponse(description,
257 Optional.of(schema)));
259 responses.set(String.valueOf(Response.Status.NO_CONTENT.getStatusCode()), buildResponse(description,
262 postOperation.set(RESPONSES_KEY, responses);
263 postOperation.put(DESCRIPTION_KEY, operDef.getDescription().orElse(""));
264 postOperation.put(SUMMARY_KEY, buildSummaryValue(HttpMethod.POST, moduleName, deviceName, operName));
265 postOperation.set(TAGS_KEY, buildTagsValue(deviceName, moduleName));
266 return postOperation;
269 private static void insertRequestBodyParameter(final ObjectNode operation, final String defName,
270 final String xmlDefName, final String name) {
271 final ObjectNode payload = JsonNodeFactory.instance.objectNode();
272 final ObjectNode content = JsonNodeFactory.instance.objectNode();
273 final JsonNode node = operation.get(SUMMARY_KEY);
274 if (node != null && node.asText().contains(HttpMethod.PATCH)) {
275 content.set("application/yang-data+json", buildMimeTypeValue(defName));
276 content.set("application/yang-data+xml", buildMimeTypeValue(xmlDefName));
278 content.set(MediaType.APPLICATION_JSON, buildMimeTypeValue(defName));
279 content.set(MediaType.APPLICATION_XML, buildMimeTypeValue(xmlDefName));
281 payload.set(CONTENT_KEY, content);
282 payload.put(DESCRIPTION_KEY, name);
283 operation.set(REQUEST_BODY_KEY, payload);
286 private static ObjectNode buildRefSchema(final String defName) {
287 final ObjectNode schema = JsonNodeFactory.instance.objectNode();
288 schema.put(REF_KEY, COMPONENTS_PREFIX + defName);
292 private static ObjectNode buildMimeTypeValue(final String defName) {
293 final ObjectNode mimeTypeValue = JsonNodeFactory.instance.objectNode();
294 mimeTypeValue.set(SCHEMA_KEY, buildRefSchema(defName));
295 return mimeTypeValue;
298 public static ObjectNode buildResponse(final String description, final Optional<ObjectNode> schema) {
299 final ObjectNode response = JsonNodeFactory.instance.objectNode();
301 if (schema.isPresent()) {
302 final ObjectNode schemaValue = schema.orElseThrow();
303 final ObjectNode content = JsonNodeFactory.instance.objectNode();
304 final ObjectNode body = JsonNodeFactory.instance.objectNode();
305 for (final String mimeType : MIME_TYPES) {
306 content.set(mimeType, body);
308 body.set(SCHEMA_KEY, schemaValue);
309 response.set(CONTENT_KEY, content);
311 response.put(DESCRIPTION_KEY, description);
315 private static String buildSummaryValue(final String httpMethod, final String moduleName,
316 final Optional<String> deviceName, final String nodeName) {
317 return httpMethod + SUMMARY_SEPARATOR + deviceName.map(s -> s + SUMMARY_SEPARATOR).orElse("")
318 + moduleName + SUMMARY_SEPARATOR + nodeName;
321 public static ArrayNode buildTagsValue(final Optional<String> deviceName, final String moduleName) {
322 final ArrayNode tagsValue = JsonNodeFactory.instance.arrayNode();
323 tagsValue.add(deviceName.map(s -> "mounted " + s).orElse("controller") + " " + moduleName);
327 public static ObjectNode getTypeParentNode(final ObjectNode parameter) {
328 final ObjectNode schema = JsonNodeFactory.instance.objectNode();
329 parameter.set(SCHEMA_KEY, schema);