Change alignments in methods declaration
[netconf.git] / restconf / sal-rest-docgen / src / main / java / org / opendaylight / netconf / sal / rest / doc / model / builder / OperationBuilder.java
index bb14d5a593e75eaac73569cb9cf652f3547b5210..861888c7ab8cb8af33166ae9043a704babe22c13 100644 (file)
 /*
- * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ * Copyright (c) 2020 PANTHEON.tech, s.r.o. and others.  All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
+
 package org.opendaylight.netconf.sal.rest.doc.model.builder;
 
-import java.util.ArrayList;
+import static org.opendaylight.netconf.sal.rest.doc.impl.DefinitionGenerator.INPUT;
+import static org.opendaylight.netconf.sal.rest.doc.impl.DefinitionGenerator.INPUT_SUFFIX;
+import static org.opendaylight.netconf.sal.rest.doc.impl.DefinitionGenerator.OUTPUT_SUFFIX;
+
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.JsonNodeFactory;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.collect.ImmutableList;
 import java.util.List;
-import org.opendaylight.netconf.sal.rest.doc.swagger.Operation;
-import org.opendaylight.netconf.sal.rest.doc.swagger.Parameter;
-import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import java.util.Optional;
+import javax.ws.rs.HttpMethod;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import org.opendaylight.netconf.sal.rest.doc.impl.ApiDocServiceImpl.OAversion;
+import org.opendaylight.netconf.sal.rest.doc.impl.DefinitionNames;
+import org.opendaylight.netconf.sal.rest.doc.util.JsonUtil;
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.InputSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.OperationDefinition;
+import org.opendaylight.yangtools.yang.model.api.OutputSchemaNode;
 
 public final class OperationBuilder {
+    public static final String BODY = "body";
+    public static final String CONFIG = "_config";
+    public static final String CONFIG_QUERY_PARAM = "config";
+    public static final String CONSUMES_KEY = "consumes";
+    public static final String CONTENT_KEY = "content";
+    public static final String COMPONENTS_PREFIX = "#/components/schemas/";
+    public static final String DEFINITIONS_PREFIX = "#/definitions/";
+    public static final String DESCRIPTION_KEY = "description";
+    public static final String IN_KEY = "in";
+    public static final String INPUT_KEY = "input";
+    public static final String NAME_KEY = "name";
+    public static final String NONCONFIG_QUERY_PARAM = "nonconfig";
+    public static final String PARAMETERS_KEY = "parameters";
+    public static final String POST_SUFFIX = "_post";
+    public static final String PROPERTIES_KEY = "properties";
+    public static final String REF_KEY = "$ref";
+    public static final String REQUEST_BODY_KEY = "requestBody";
+    public static final String RESPONSES_KEY = "responses";
+    public static final String SCHEMA_KEY = "schema";
+    public static final String SUMMARY_KEY = "summary";
+    public static final String SUMMARY_SEPARATOR = " - ";
+    public static final String TAGS_KEY = "tags";
+    public static final String TOP = "_TOP";
+    public static final String XML_KEY = "xml";
+    public static final String XML_SUFFIX = "_xml";
+    private static final String CONTENT = "content";
+    private static final ArrayNode CONSUMES_PUT_POST;
+    private static final String ENUM_KEY = "enum";
+    private static final List<String> MIME_TYPES = ImmutableList.of(MediaType.APPLICATION_XML,
+            MediaType.APPLICATION_JSON);
+    private static final String OBJECT = "object";
+    private static final String REQUIRED_KEY = "required";
+    private static final String STRING = "string";
+    private static final String TYPE_KEY = "type";
+    private static final String QUERY = "query";
 
-    public static final String OPERATIONAL = "(operational)";
-    public static final String CONFIG = "(config)";
-    public static final String TOP = "-TOP";
+    static {
+        CONSUMES_PUT_POST = JsonNodeFactory.instance.arrayNode();
+        for (final String mimeType : MIME_TYPES) {
+            CONSUMES_PUT_POST.add(mimeType);
+        }
+    }
 
-    public static final List<String> CONSUMES_PUT_POST = new ArrayList<>();
+    private OperationBuilder() {
 
-    static {
-        CONSUMES_PUT_POST.add("application/json");
-        CONSUMES_PUT_POST.add("application/xml");
     }
 
-    public static class Get {
+    public static ObjectNode buildPost(final String parentName, final String nodeName, final String discriminator,
+            final String moduleName, final Optional<String> deviceName, final String description,
+            final ArrayNode pathParams, final OAversion oaversion) {
+        final ObjectNode value = JsonNodeFactory.instance.objectNode();
+        value.put(DESCRIPTION_KEY, description);
+        value.put(SUMMARY_KEY, buildSummaryValue(HttpMethod.POST, moduleName, deviceName, nodeName));
+        value.set(TAGS_KEY, buildTagsValue(deviceName, moduleName));
+        final ArrayNode parameters = JsonUtil.copy(pathParams);
+        final ObjectNode ref = JsonNodeFactory.instance.objectNode();
+        final String cleanDefName = parentName + CONFIG + "_" + nodeName + POST_SUFFIX;
+        final String defName = cleanDefName + discriminator;
+        final String xmlDefName = cleanDefName + XML_SUFFIX + discriminator;
+        ref.put(REF_KEY, getAppropriateModelPrefix(oaversion) + defName);
+        insertRequestBodyParameter(parameters, value, defName, xmlDefName, nodeName + CONFIG, oaversion);
+        value.set(PARAMETERS_KEY, parameters);
 
-        protected Operation spec;
-        protected DataSchemaNode schemaNode;
-        private static final String METHOD_NAME = "GET";
+        final ObjectNode responses = JsonNodeFactory.instance.objectNode();
+        responses.set(String.valueOf(Response.Status.CREATED.getStatusCode()),
+                buildResponse(Response.Status.CREATED.getReasonPhrase(), Optional.empty(), oaversion));
 
-        public Get(final DataSchemaNode node, final boolean isConfig) {
-            this.schemaNode = node;
-            spec = new Operation();
-            spec.setMethod(METHOD_NAME);
-            spec.setNickname(METHOD_NAME + "-" + node.getQName().getLocalName());
-            spec.setType((isConfig ? CONFIG : OPERATIONAL) + node.getQName().getLocalName());
-            spec.setNotes(node.getDescription());
-        }
+        value.set(RESPONSES_KEY, responses);
+        setConsumesIfNeeded(value, oaversion);
+        return value;
+    }
 
-        public Get pathParams(final List<Parameter> params) {
-            final List<Parameter> pathParameters = new ArrayList<>(params);
-            spec.setParameters(pathParameters);
-            return this;
-        }
+    public static ObjectNode buildGet(final DataSchemaNode node, final String moduleName,
+            final Optional<String> deviceName, final ArrayNode pathParams, final String defName,
+            final boolean isConfig, final OAversion oaversion) {
+        final ObjectNode value = JsonNodeFactory.instance.objectNode();
+        value.put(DESCRIPTION_KEY, node.getDescription().orElse(""));
+        value.put(SUMMARY_KEY, buildSummaryValue(HttpMethod.GET, moduleName, deviceName,
+                node.getQName().getLocalName()));
+        value.set(TAGS_KEY, buildTagsValue(deviceName, moduleName));
+        final ArrayNode parameters = JsonUtil.copy(pathParams);
+
+        addQueryParameters(parameters, isConfig, oaversion);
+
+        value.set(PARAMETERS_KEY, parameters);
 
-        public Operation build() {
-            return spec;
+        final ObjectNode responses = JsonNodeFactory.instance.objectNode();
+        final ObjectNode schema = JsonNodeFactory.instance.objectNode();
+        schema.put(REF_KEY, getAppropriateModelPrefix(oaversion) + defName);
+        responses.set(String.valueOf(Response.Status.OK.getStatusCode()),
+                buildResponse(Response.Status.OK.getReasonPhrase(), Optional.of(schema), oaversion));
+
+        value.set(RESPONSES_KEY, responses);
+        return value;
+    }
+
+    private static void addQueryParameters(final ArrayNode parameters, final boolean isConfig,
+            final OAversion oaversion) {
+        final ObjectNode contentParam = JsonNodeFactory.instance.objectNode();
+        final ArrayNode cases = JsonNodeFactory.instance.arrayNode();
+        cases.add(NONCONFIG_QUERY_PARAM);
+        if (isConfig) {
+            cases.add(CONFIG_QUERY_PARAM);
+        } else {
+            contentParam.put(REQUIRED_KEY, true);
         }
+        contentParam.put(IN_KEY, QUERY);
+        contentParam.put(NAME_KEY, CONTENT);
+
+        final ObjectNode typeParent = getTypeParentNode(contentParam, oaversion);
+        typeParent.put(TYPE_KEY, STRING);
+        typeParent.set(ENUM_KEY, cases);
+
+        parameters.add(contentParam);
     }
 
-    public static class Put {
-        protected Operation spec;
-        protected String nodeName;
-        protected String parentName;
-        private static final String METHOD_NAME = "PUT";
+    public static ObjectNode buildPut(final String parentName, final String nodeName, final String discriminator,
+            final String moduleName, final Optional<String> deviceName, final String description,
+            final ArrayNode pathParams, final OAversion oaversion) {
+        final ObjectNode value = JsonNodeFactory.instance.objectNode();
+        value.put(DESCRIPTION_KEY, description);
+        value.put(SUMMARY_KEY, buildSummaryValue(HttpMethod.PUT, moduleName, deviceName, nodeName));
+        value.set(TAGS_KEY, buildTagsValue(deviceName, moduleName));
+        final ArrayNode parameters = JsonUtil.copy(pathParams);
+        final String defName = parentName + CONFIG + "_" + nodeName + TOP;
+        final String xmlDefName = parentName + CONFIG + "_" + nodeName;
+        insertRequestBodyParameter(parameters, value, defName, xmlDefName, nodeName + CONFIG, oaversion);
+        value.set(PARAMETERS_KEY, parameters);
 
-        public Put(final String nodeName, final String description, final String parentName) {
-            this.nodeName = nodeName;
-            this.parentName = parentName;
-            spec = new Operation();
-            spec.setType(parentName + CONFIG + nodeName + TOP);
-            spec.setNotes(description);
-            spec.setConsumes(CONSUMES_PUT_POST);
-        }
+        final ObjectNode responses = JsonNodeFactory.instance.objectNode();
+        responses.set(String.valueOf(Response.Status.CREATED.getStatusCode()),
+                buildResponse(Response.Status.CREATED.getReasonPhrase(), Optional.empty(), oaversion));
+        responses.set(String.valueOf(Response.Status.NO_CONTENT.getStatusCode()),
+                buildResponse("Updated", Optional.empty(), oaversion));
 
-        public Put pathParams(final List<Parameter> params) {
-            final List<Parameter> parameters = new ArrayList<>(params);
-            final Parameter payload = new Parameter();
-            payload.setParamType("body");
-            payload.setType(parentName + CONFIG + nodeName + TOP);
-            payload.setName(CONFIG + nodeName);
-            parameters.add(payload);
-            spec.setParameters(parameters);
-            return this;
-        }
+        value.set(RESPONSES_KEY, responses);
+        setConsumesIfNeeded(value, oaversion);
+        return value;
+    }
 
-        public Operation build() {
-            spec.setMethod(METHOD_NAME);
-            spec.setNickname(METHOD_NAME + "-" + nodeName);
-            return spec;
-        }
+    public static ObjectNode buildDelete(final DataSchemaNode node, final String moduleName,
+            final Optional<String> deviceName, final ArrayNode pathParams, final OAversion oaversion) {
+        final ObjectNode value = JsonNodeFactory.instance.objectNode();
+        value.put(SUMMARY_KEY, buildSummaryValue(HttpMethod.DELETE, moduleName, deviceName,
+                node.getQName().getLocalName()));
+        value.set(TAGS_KEY, buildTagsValue(deviceName, moduleName));
+        value.put(DESCRIPTION_KEY, node.getDescription().orElse(""));
+        final ArrayNode parameters = JsonUtil.copy(pathParams);
+        value.set(PARAMETERS_KEY, parameters);
+
+        final ObjectNode responses = JsonNodeFactory.instance.objectNode();
+        responses.set(String.valueOf(Response.Status.NO_CONTENT.getStatusCode()),
+                buildResponse("Deleted", Optional.empty(), oaversion));
+
+        value.set(RESPONSES_KEY, responses);
+        return value;
     }
 
-    public static final class Post extends Put {
+    public static ObjectNode buildPostOperation(final OperationDefinition operDef, final String moduleName,
+            final Optional<String> deviceName, final String parentName, final DefinitionNames definitionNames,
+            final OAversion oaversion) {
+        final ObjectNode postOperation = JsonNodeFactory.instance.objectNode();
+        final ArrayNode parameters = JsonNodeFactory.instance.arrayNode();
+        final String operName = operDef.getQName().getLocalName();
+        final String inputName = operName + INPUT_SUFFIX;
+
+        final InputSchemaNode input = operDef.getInput();
+        final OutputSchemaNode output = operDef.getOutput();
+        if (!input.getChildNodes().isEmpty()) {
+            final String discriminator = definitionNames.getDiscriminator(input);
+            final String clearDefName = parentName + "_" + operName + INPUT_SUFFIX;
+            final String defName = clearDefName + discriminator;
+            final String defTopName = clearDefName + TOP + discriminator;
+            insertRequestBodyParameter(parameters, postOperation, defTopName, defName, inputName, oaversion);
+        } else {
+            final ObjectNode payload = JsonNodeFactory.instance.objectNode();
+            final ObjectNode jsonSchema = JsonNodeFactory.instance.objectNode();
+            final ObjectNode properties = JsonNodeFactory.instance.objectNode();
+            final ObjectNode inputSchema = JsonNodeFactory.instance.objectNode();
+            inputSchema.put(TYPE_KEY, OBJECT);
+            properties.set(INPUT_KEY, inputSchema);
+            jsonSchema.put(TYPE_KEY, OBJECT);
+            jsonSchema.set(PROPERTIES_KEY, properties);
+            if (oaversion.equals(OAversion.V3_0)) {
+                final ObjectNode content = JsonNodeFactory.instance.objectNode();
+                final ObjectNode jsonTypeValue = JsonNodeFactory.instance.objectNode();
+                jsonTypeValue.set(SCHEMA_KEY, jsonSchema);
+                content.set(MediaType.APPLICATION_JSON, jsonTypeValue);
+
+                final ObjectNode xmlSchema = JsonNodeFactory.instance.objectNode();
+                xmlSchema.put(TYPE_KEY, OBJECT);
+                final ObjectNode xml = JsonNodeFactory.instance.objectNode();
+                xml.put(NAME_KEY, INPUT);
+                xmlSchema.set(XML_KEY, xml);
+                final ObjectNode xmlTypeValue = JsonNodeFactory.instance.objectNode();
+                xmlTypeValue.set(SCHEMA_KEY, xmlSchema);
+                content.set(MediaType.APPLICATION_XML, xmlTypeValue);
+
+                payload.set(CONTENT_KEY, content);
+                payload.put(DESCRIPTION_KEY, inputName);
+                postOperation.set(REQUEST_BODY_KEY, payload);
+            } else {
+                payload.put(IN_KEY, BODY);
+                payload.put(NAME_KEY, inputName);
+                payload.set(SCHEMA_KEY, jsonSchema);
+                parameters.add(payload);
+            }
 
-        public static final String METHOD_NAME = "POST";
-        private final DataNodeContainer dataNodeContainer;
+        }
+        setConsumesIfNeeded(postOperation, oaversion);
+        postOperation.set(PARAMETERS_KEY, parameters);
+        final ObjectNode responses = JsonNodeFactory.instance.objectNode();
+        final String description = String.format("RPC %s success", operName);
 
-        public Post(final String nodeName, final String parentName, final String description,
-                    final DataNodeContainer dataNodeContainer) {
-            super(nodeName, description, parentName.replace("_module", ""));
-            this.dataNodeContainer = dataNodeContainer;
-            spec.setType(CONFIG + nodeName + METHOD_NAME);
-            spec.setConsumes(CONSUMES_PUT_POST);
+        if (!output.getChildNodes().isEmpty()) {
+            final ObjectNode schema = JsonNodeFactory.instance.objectNode();
+            final String defName = parentName + "_" + operName + OUTPUT_SUFFIX + TOP
+                    + definitionNames.getDiscriminator(output);
+            schema.put(REF_KEY, getAppropriateModelPrefix(oaversion) + defName);
+            responses.set(String.valueOf(Response.Status.OK.getStatusCode()), buildResponse(description,
+                    Optional.of(schema), oaversion));
+        } else {
+            responses.set(String.valueOf(Response.Status.NO_CONTENT.getStatusCode()), buildResponse(description,
+                    Optional.empty(), oaversion));
         }
+        postOperation.set(RESPONSES_KEY, responses);
+        postOperation.put(DESCRIPTION_KEY, operDef.getDescription().orElse(""));
+        postOperation.put(SUMMARY_KEY, buildSummaryValue(HttpMethod.POST, moduleName, deviceName, operName));
+        postOperation.set(TAGS_KEY, buildTagsValue(deviceName, moduleName));
+        return postOperation;
+    }
 
-        @Override
-        public Operation build() {
-            spec.setMethod(METHOD_NAME);
-            spec.setNickname(METHOD_NAME + "-" + nodeName);
-            return spec;
+    private static void insertRequestBodyParameter(final ArrayNode parameters, final ObjectNode operation,
+            final String defName, final String xmlDefName, final String name, final OAversion oaversion) {
+        final ObjectNode payload = JsonNodeFactory.instance.objectNode();
+        if (oaversion.equals(OAversion.V3_0)) {
+            final ObjectNode content = JsonNodeFactory.instance.objectNode();
+            content.set(MediaType.APPLICATION_JSON, buildMimeTypeValue(defName));
+            content.set(MediaType.APPLICATION_XML, buildMimeTypeValue(xmlDefName));
+            payload.set(CONTENT_KEY, content);
+            payload.put(DESCRIPTION_KEY, name);
+            operation.set(REQUEST_BODY_KEY, payload);
+        } else {
+            payload.put(IN_KEY, BODY);
+            payload.put(NAME_KEY, name);
+            payload.set(SCHEMA_KEY, buildRefSchema(defName, OAversion.V2_0));
+            parameters.add(payload);
         }
+    }
 
-        @Override
-        public Put pathParams(final List<Parameter> params) {
-            final List<Parameter> parameters = new ArrayList<>(params);
-            for (final DataSchemaNode node : dataNodeContainer.getChildNodes()) {
-                if (node instanceof ListSchemaNode || node instanceof ContainerSchemaNode) {
-                    final Parameter payload = new Parameter();
-                    payload.setParamType("body");
-                    payload.setType(parentName + CONFIG + node.getQName().getLocalName() + TOP);
-                    payload.setName("**" + CONFIG + node.getQName().getLocalName());
-                    parameters.add(payload);
+    private static ObjectNode buildRefSchema(final String defName, final OAversion oaversion) {
+        final ObjectNode schema = JsonNodeFactory.instance.objectNode();
+        schema.put(REF_KEY, getAppropriateModelPrefix(oaversion) + defName);
+        return schema;
+    }
+
+    private static ObjectNode buildMimeTypeValue(final String defName) {
+        final ObjectNode mimeTypeValue = JsonNodeFactory.instance.objectNode();
+        mimeTypeValue.set(SCHEMA_KEY, buildRefSchema(defName, OAversion.V3_0));
+        return mimeTypeValue;
+    }
+
+    public static ObjectNode buildResponse(final String description, final Optional<ObjectNode> schema,
+            final OAversion oaversion) {
+        final ObjectNode response = JsonNodeFactory.instance.objectNode();
+
+        if (schema.isPresent()) {
+            final ObjectNode schemaValue = schema.get();
+            if (oaversion.equals(OAversion.V3_0)) {
+                final ObjectNode content = JsonNodeFactory.instance.objectNode();
+                final ObjectNode body = JsonNodeFactory.instance.objectNode();
+                for (final String mimeType : MIME_TYPES) {
+                    content.set(mimeType, body);
                 }
+                body.set(SCHEMA_KEY, schemaValue);
+                response.set(CONTENT_KEY, content);
+            } else {
+                response.set(SCHEMA_KEY, schemaValue);
             }
-            spec.setParameters(parameters);
-            return this;
         }
+        response.put(DESCRIPTION_KEY, description);
+        return response;
+    }
 
-        public Post summary(final String summary) {
-            spec.setSummary(summary);
-            return this;
+    private static void setConsumesIfNeeded(final ObjectNode operation, final OAversion oaversion) {
+        if (oaversion.equals(OAversion.V2_0)) {
+            operation.set(CONSUMES_KEY, CONSUMES_PUT_POST);
         }
     }
 
-    public static final class Delete extends Get {
-        private static final String METHOD_NAME = "DELETE";
+    private static String buildSummaryValue(final String httpMethod, final String moduleName,
+            final Optional<String> deviceName, final String nodeName) {
+        return httpMethod + SUMMARY_SEPARATOR + deviceName.map(s -> s + SUMMARY_SEPARATOR).orElse("")
+                + moduleName + SUMMARY_SEPARATOR + nodeName;
+    }
 
-        public Delete(final DataSchemaNode node) {
-            super(node, false);
+    public static ArrayNode buildTagsValue(final Optional<String> deviceName, final String moduleName) {
+        final ArrayNode tagsValue = JsonNodeFactory.instance.arrayNode();
+        tagsValue.add(deviceName.map(s -> "mounted " + s).orElse("controller") + " " + moduleName);
+        return tagsValue;
+    }
+
+    public static String getAppropriateModelPrefix(final OAversion oaversion) {
+        if (oaversion.equals(OAversion.V3_0)) {
+            return COMPONENTS_PREFIX;
         }
+        return DEFINITIONS_PREFIX;
+    }
 
-        @Override
-        public Operation build() {
-            spec.setMethod(METHOD_NAME);
-            spec.setNickname(METHOD_NAME + "-" + schemaNode.getQName().getLocalName());
-            spec.setType(null);
-            return spec;
+    public static ObjectNode getTypeParentNode(final ObjectNode parameter, final OAversion oaversion) {
+        if (oaversion.equals(OAversion.V3_0)) {
+            final ObjectNode schema = JsonNodeFactory.instance.objectNode();
+            parameter.set(SCHEMA_KEY, schema);
+            return schema;
         }
+        return parameter;
     }
 }