--- /dev/null
+/*
+ * Copyright (c) 2023 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.restconf.openapi.model;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import java.util.Map;
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public record Link(
+ String operationRef,
+ String operationId,
+ Map<String, Object> parameters,
+ RequestBody requestBody,
+ String description,
+ Server server) {
+}
--- /dev/null
+/*
+ * Copyright (c) 2023 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.restconf.openapi.model;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import org.eclipse.jdt.annotation.Nullable;
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public record MediaTypeObject(
+ @Nullable Schema schema) {
+
+ private MediaTypeObject(final Builder builder) {
+ this(builder.schema);
+ }
+
+ @SuppressWarnings("checkstyle:hiddenField")
+ public static class Builder {
+ Schema schema;
+
+ public Builder schema(Schema schema) {
+ this.schema = schema;
+ return this;
+ }
+
+ public MediaTypeObject build() {
+ return new MediaTypeObject(this);
+ }
+ }
+}
package org.opendaylight.restconf.openapi.model;
import com.fasterxml.jackson.annotation.JsonInclude;
-import com.fasterxml.jackson.databind.node.ArrayNode;
-import com.fasterxml.jackson.databind.node.ObjectNode;
import java.util.List;
import java.util.Map;
List<String> tags,
List<Parameter> parameters,
List<Map<String, List<String>>> security,
- ArrayNode servers,
- ObjectNode callbacks,
- ObjectNode externalDocs,
- ObjectNode requestBody,
- ObjectNode responses,
+ List<Server> servers,
+ Map<String, Path> callbacks,
+ ExternalDocumentation externalDocs,
+ RequestBody requestBody,
+ Map<String, ResponseObject> responses,
String description,
String operationId,
String summary) {
+ public Operation {
+ tags = tags == null ? null : List.copyOf(tags);
+ parameters = parameters == null ? null : List.copyOf(parameters);
+ security = security == null ? null : List.copyOf(security);
+ servers = servers == null ? null : List.copyOf(servers);
+ callbacks = callbacks == null ? null : Map.copyOf(callbacks);
+ responses = responses == null ? null : Map.copyOf(responses);
+ }
+
private Operation(final Builder builder) {
this(builder.deprecated, builder.tags, builder.parameters, builder.security, builder.servers, builder.callbacks,
builder.externalDocs, builder.requestBody, builder.responses, builder.description, builder.operationId,
private List<String> tags;
private List<Parameter> parameters;
private List<Map<String, List<String>>> security;
- private ArrayNode servers;
- private ObjectNode callbacks;
- private ObjectNode externalDocs;
- private ObjectNode requestBody;
- private ObjectNode responses;
+ private List<Server> servers;
+ private Map<String, Path> callbacks;
+ private ExternalDocumentation externalDocs;
+ private RequestBody requestBody;
+ private Map<String, ResponseObject> responses;
private String description;
private String operationId;
private String summary;
return this;
}
- public Builder servers(final ArrayNode servers) {
+ public Builder servers(final List<Server> servers) {
this.servers = servers;
return this;
}
- public Builder callbacks(final ObjectNode callbacks) {
+ public Builder callbacks(final Map<String, Path> callbacks) {
this.callbacks = callbacks;
return this;
}
- public Builder externalDocs(final ObjectNode externalDocs) {
+ public Builder externalDocs(final ExternalDocumentation externalDocs) {
this.externalDocs = externalDocs;
return this;
}
- public Builder requestBody(final ObjectNode requestBody) {
+ public Builder requestBody(final RequestBody requestBody) {
this.requestBody = requestBody;
return this;
}
- public Builder responses(final ObjectNode responses) {
+ public Builder responses(final Map<String, ResponseObject> responses) {
this.responses = responses;
return this;
}
--- /dev/null
+/*
+ * Copyright (c) 2023 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.restconf.openapi.model;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import java.util.Map;
+import java.util.Objects;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public record RequestBody(
+ @Nullable String description,
+ @NonNull Map<String, MediaTypeObject> content,
+ boolean required) {
+
+ public RequestBody {
+ content = Map.copyOf(Objects.requireNonNull(content));
+ }
+
+ private RequestBody(final Builder builder) {
+ this(builder.description, builder.content, builder.required);
+ }
+
+ @SuppressWarnings("checkstyle:hiddenField")
+ public static class Builder {
+ private String description;
+ private Map<String, MediaTypeObject> content;
+ private boolean required;
+
+ public Builder description(final String description) {
+ this.description = description;
+ return this;
+ }
+
+ public Builder content(final Map<String, MediaTypeObject> content) {
+ this.content = content;
+ return this;
+ }
+
+ public Builder required(final boolean required) {
+ this.required = required;
+ return this;
+ }
+
+ public RequestBody build() {
+ return new RequestBody(this);
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2023 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.restconf.openapi.model;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import java.util.Map;
+import java.util.Objects;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public record ResponseObject(
+ @NonNull String description,
+ @Nullable Map<String, String> headers,
+ @Nullable Map<String, MediaTypeObject> content,
+ @Nullable Map<String, Link> links) {
+
+ public ResponseObject {
+ description = Objects.requireNonNull(description);
+ headers = headers == null ? null : Map.copyOf(headers);
+ content = content == null ? null : Map.copyOf(content);
+ links = links == null ? null : Map.copyOf(links);
+ }
+
+ private ResponseObject(final Builder builder) {
+ this(builder.description, builder.headers, builder.content, builder.links);
+ }
+
+ @SuppressWarnings("checkstyle:hiddenField")
+ public static class Builder {
+ private String description;
+ private Map<String, String> headers;
+ private Map<String, MediaTypeObject> content;
+ private Map<String, Link> links;
+
+ public Builder description(final String description) {
+ this.description = description;
+ return this;
+ }
+
+ public Builder headers(final Map<String, String> headers) {
+ this.headers = headers;
+ return this;
+ }
+
+ public Builder content(final Map<String, MediaTypeObject> content) {
+ this.content = content;
+ return this;
+ }
+
+ public Builder links(final Map<String, Link> links) {
+ this.links = links;
+ return this;
+ }
+
+ public ResponseObject build() {
+ return new ResponseObject(this);
+ }
+ }
+}
*/
package org.opendaylight.restconf.openapi.model.builder;
-import static org.opendaylight.restconf.openapi.impl.DefinitionGenerator.INPUT;
+import static javax.ws.rs.core.Response.Status.NO_CONTENT;
+import static javax.ws.rs.core.Response.Status.OK;
import static org.opendaylight.restconf.openapi.impl.DefinitionGenerator.INPUT_SUFFIX;
import static org.opendaylight.restconf.openapi.impl.DefinitionGenerator.OUTPUT_SUFFIX;
-import com.fasterxml.jackson.databind.node.JsonNodeFactory;
-import com.fasterxml.jackson.databind.node.ObjectNode;
+import java.util.AbstractMap.SimpleEntry;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import javax.ws.rs.HttpMethod;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.eclipse.jdt.annotation.NonNull;
import org.opendaylight.restconf.openapi.impl.DefinitionNames;
+import org.opendaylight.restconf.openapi.model.MediaTypeObject;
import org.opendaylight.restconf.openapi.model.Operation;
import org.opendaylight.restconf.openapi.model.Parameter;
+import org.opendaylight.restconf.openapi.model.Property;
+import org.opendaylight.restconf.openapi.model.RequestBody;
+import org.opendaylight.restconf.openapi.model.ResponseObject;
import org.opendaylight.restconf.openapi.model.Schema;
+import org.opendaylight.restconf.openapi.model.Xml;
import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
import org.opendaylight.yangtools.yang.model.api.OutputSchemaNode;
public final class OperationBuilder {
- public static final String CONTENT_KEY = "content";
public static final String COMPONENTS_PREFIX = "#/components/schemas/";
- public static final String DESCRIPTION_KEY = "description";
public static final String INPUT_KEY = "input";
- public static final String NAME_KEY = "name";
- public static final String PROPERTIES_KEY = "properties";
- public static final String REF_KEY = "$ref";
- public static final String SCHEMA_KEY = "schema";
public static final String SUMMARY_TEMPLATE = "%s - %s - %s - %s";
- public static final String XML_KEY = "xml";
private static final List<String> MIME_TYPES = List.of(MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON);
private static final String OBJECT = "object";
- private static final String TYPE_KEY = "type";
private static final String POST_DESCRIPTION = """
\n
Note:
final var summary = SUMMARY_TEMPLATE.formatted(HttpMethod.POST, deviceName, moduleName, nodeName);
final List<String> tags = List.of(deviceName + " " + moduleName);
final List<Parameter> parameters = new ArrayList<>(pathParams);
- final ObjectNode requestBody;
+ final RequestBody requestBody;
final DataSchemaNode childNode = node == null ? null : getListOrContainerChildNode(node);
final List<String> nameElements = new ArrayList<>();
if (parentName != null) {
final String defName = String.join("_", nameElements);
requestBody = createPostDataRequestBodyParameter(defName, nodeName);
}
- final ObjectNode responses = JsonNodeFactory.instance.objectNode();
- responses.set(String.valueOf(Response.Status.CREATED.getStatusCode()),
- buildResponse(Response.Status.CREATED.getReasonPhrase()));
+ final Map<String, ResponseObject> responses = Map.of(String.valueOf(Response.Status.CREATED.getStatusCode()),
+ buildResponse(Response.Status.CREATED.getReasonPhrase()));
return new Operation.Builder()
.tags(tags)
final List<String> tags = List.of(deviceName + " " + moduleName);
final List<Parameter> parameters = new ArrayList<>(pathParams);
parameters.add(buildQueryParameters(isConfig));
- final ObjectNode responses = JsonNodeFactory.instance.objectNode();
-
final boolean isList = node instanceof ListSchemaNode;
- final ObjectNode response = createRequestBodyParameter(defName, nodeName, isList, summary,
- String.valueOf(Response.Status.OK.getStatusCode()));
- responses.set(String.valueOf(Response.Status.OK.getStatusCode()), response);
+ final ResponseObject response = createResponse(defName, nodeName, isList,
+ String.valueOf(OK.getStatusCode()), summary);
+ final Map<String, ResponseObject> responses = Map.of(String.valueOf(OK.getStatusCode()),
+ response);
return new Operation.Builder()
.tags(tags)
final List<Parameter> parameters = new ArrayList<>(pathParams);
final String defName = parentName + "_" + nodeName;
final boolean isList = node instanceof ListSchemaNode;
- final ObjectNode requestBody = createRequestBodyParameter(defName, fullName, isList, summary, nodeName);
+ final RequestBody requestBody = createRequestBodyParameter(defName, fullName, isList, summary, nodeName);
- final ObjectNode responses = JsonNodeFactory.instance.objectNode();
- responses.set(String.valueOf(Response.Status.CREATED.getStatusCode()),
+ final var created = new SimpleEntry<>(String.valueOf(Response.Status.CREATED.getStatusCode()),
buildResponse(Response.Status.CREATED.getReasonPhrase()));
- responses.set(String.valueOf(Response.Status.NO_CONTENT.getStatusCode()), buildResponse("Updated"));
+ final var updated = new SimpleEntry<>(String.valueOf(NO_CONTENT.getStatusCode()),
+ buildResponse("Updated"));
return new Operation.Builder()
.tags(tags)
.parameters(parameters)
.requestBody(requestBody)
- .responses(responses)
+ .responses(Map.of(created.getKey(), created.getValue(), updated.getKey(), updated.getValue()))
.description(node.getDescription().orElse(""))
.summary(summary)
.build();
final List<Parameter> parameters = new ArrayList<>(pathParams);
final String defName = parentName + "_" + nodeName;
final boolean isList = node instanceof ListSchemaNode;
- final ObjectNode requestBody = createRequestBodyParameter(defName, fullName, isList, summary, nodeName);
+ final RequestBody requestBody = createRequestBodyParameter(defName, fullName, isList, summary, nodeName);
- final ObjectNode responses = JsonNodeFactory.instance.objectNode();
- responses.set(String.valueOf(Response.Status.OK.getStatusCode()),
- buildResponse(Response.Status.OK.getReasonPhrase()));
- responses.set(String.valueOf(Response.Status.NO_CONTENT.getStatusCode()), buildResponse("Updated"));
+ final SimpleEntry<String, ResponseObject> created = new SimpleEntry<>(String.valueOf(OK.getStatusCode()),
+ buildResponse(OK.getReasonPhrase()));
+ final SimpleEntry<String, ResponseObject> updated = new SimpleEntry<>(String.valueOf(NO_CONTENT
+ .getStatusCode()), buildResponse("Updated"));
return new Operation.Builder()
.tags(tags)
.parameters(parameters)
.requestBody(requestBody)
- .responses(responses)
+ .responses(Map.of(created.getKey(), created.getValue(), updated.getKey(), updated.getValue()))
.description(node.getDescription().orElse(""))
.summary(summary)
.build();
final List<String> tags = List.of(deviceName + " " + moduleName);
final String description = node.getDescription().orElse("");
final List<Parameter> parameters = new ArrayList<>(pathParams);
-
- final ObjectNode responses = JsonNodeFactory.instance.objectNode();
- responses.set(String.valueOf(Response.Status.NO_CONTENT.getStatusCode()), buildResponse("Deleted"));
+ final Map<String, ResponseObject> responses = Map.of(String.valueOf(NO_CONTENT.getStatusCode()),
+ buildResponse("Deleted"));
return new Operation.Builder()
.tags(tags)
final InputSchemaNode input = operDef.getInput();
final OutputSchemaNode output = operDef.getOutput();
- ObjectNode requestBody;
+ final RequestBody requestBody;
if (!input.getChildNodes().isEmpty()) {
final String discriminator = definitionNames.getDiscriminator(input);
final String clearDefName = parentName + "_" + operationName + INPUT_SUFFIX;
final String defName = clearDefName + discriminator;
requestBody = createRequestBodyParameter(defName, INPUT_KEY, false, summary, inputName);
} 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);
- 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);
- requestBody = payload;
+ final Map<String, Property> properties = Map.of(INPUT_KEY, new Property.Builder().type(OBJECT).build());
+ final Schema jsonSchema = new Schema.Builder()
+ .type(OBJECT)
+ .properties(properties)
+ .build();
+ final MediaTypeObject jsonTypeValue = new MediaTypeObject.Builder()
+ .schema(jsonSchema)
+ .build();
+ final SimpleEntry<String, MediaTypeObject> jsonEntry = new SimpleEntry<>(MediaType.APPLICATION_JSON,
+ jsonTypeValue);
+
+ final Xml xml = new Xml(INPUT_KEY, null, null);
+ final Schema xmlSchema = new Schema.Builder()
+ .type(OBJECT)
+ .xml(xml)
+ .build();
+ final MediaTypeObject xmlTypeValue = new MediaTypeObject.Builder()
+ .schema(xmlSchema)
+ .build();
+ final SimpleEntry<String, MediaTypeObject> xmlEntry = new SimpleEntry<>(MediaType.APPLICATION_XML,
+ xmlTypeValue);
+
+ requestBody = new RequestBody.Builder()
+ .content(Map.of(jsonEntry.getKey(), jsonEntry.getValue(), xmlEntry.getKey(), xmlEntry.getValue()))
+ .description(inputName)
+ .build();
}
- final ObjectNode responses = JsonNodeFactory.instance.objectNode();
final String description = String.format("RPC %s success", operationName);
+ final Map<String, ResponseObject> responses;
if (!output.getChildNodes().isEmpty()) {
- final ObjectNode schema = JsonNodeFactory.instance.objectNode();
final String defName = parentName + "_" + operationName + OUTPUT_SUFFIX
- + definitionNames.getDiscriminator(output);
- schema.put(REF_KEY, COMPONENTS_PREFIX + defName);
- responses.set(String.valueOf(Response.Status.OK.getStatusCode()), buildResponse(description, schema));
+ + definitionNames.getDiscriminator(output);
+ final Schema schema = new Schema.Builder()
+ .ref(COMPONENTS_PREFIX + defName)
+ .build();
+ responses = Map.of(String.valueOf(OK.getStatusCode()), buildResponse(description, schema));
} else {
- responses.set(String.valueOf(Response.Status.NO_CONTENT.getStatusCode()), buildResponse(description));
+ responses = Map.of(String.valueOf(NO_CONTENT.getStatusCode()), buildResponse(description));
}
final String desc = operDef.getDescription().orElse("");
final List<String> tags = List.of(deviceName + " " + moduleName);
.build();
}
- private static ObjectNode createPostDataRequestBodyParameter(final String defName, final String name) {
- final ObjectNode payload = JsonNodeFactory.instance.objectNode();
- final ObjectNode content = JsonNodeFactory.instance.objectNode();
- final ObjectNode value = buildMimeTypeValue(defName);
- content.set(MediaType.APPLICATION_JSON, value);
- content.set(MediaType.APPLICATION_XML, value);
- payload.set(CONTENT_KEY, content);
- payload.put(DESCRIPTION_KEY, name);
- return payload;
+ private static RequestBody createPostDataRequestBodyParameter(final String defName, final String name) {
+ final MediaTypeObject value = buildMediaTypeObject(defName);
+ final Map<String, MediaTypeObject> content = Map.of(MediaType.APPLICATION_JSON, value,
+ MediaType.APPLICATION_XML, value);
+ return new RequestBody.Builder()
+ .content(content)
+ .description(name)
+ .build();
}
- private static ObjectNode createRequestBodyParameter(final String defName, final String name,
+ private static RequestBody createRequestBodyParameter(final String defName, final String name,
final boolean isList, final String summary, final String description) {
- final ObjectNode payload = JsonNodeFactory.instance.objectNode();
- final ObjectNode content = JsonNodeFactory.instance.objectNode();
- final ObjectNode properties = JsonNodeFactory.instance.objectNode();
+ final Map<String, MediaTypeObject> content = getStringMediaTypeObjectMap(defName, name, isList, summary);
+ return new RequestBody.Builder()
+ .content(content)
+ .description(description)
+ .build();
+ }
+
+ private static ResponseObject createResponse(final String defName, final String name,
+ final boolean isList, final String description, final String summary) {
+ final Map<String, MediaTypeObject> content = getStringMediaTypeObjectMap(defName, name, isList, summary);
+ return new ResponseObject.Builder()
+ .content(content)
+ .description(description)
+ .build();
+ }
+
+ private static Map<String, MediaTypeObject> getStringMediaTypeObjectMap(final String defName, final String name,
+ final boolean isList, final String summary) {
+ final Map<String, Property> properties;
if (isList) {
- final ObjectNode list = JsonNodeFactory.instance.objectNode();
- final ObjectNode listValue = JsonNodeFactory.instance.objectNode();
- listValue.put(TYPE_KEY, "array");
- listValue.set("items", buildRefSchema(defName));
- list.set(name, listValue);
- properties.set(PROPERTIES_KEY, list);
+ properties = Map.of(name, new Property.Builder()
+ .type("array")
+ .items(new Property.Builder()
+ .type(OBJECT)
+ .ref(COMPONENTS_PREFIX + defName)
+ .build())
+ .build());
} else {
- final ObjectNode container = JsonNodeFactory.instance.objectNode();
- container.set(name, buildRefSchema(defName));
- properties.set(PROPERTIES_KEY, container);
+ properties = Map.of(name, new Property.Builder()
+ .type(OBJECT)
+ .ref(COMPONENTS_PREFIX + defName)
+ .build());
}
- final ObjectNode jsonSchema = JsonNodeFactory.instance.objectNode();
- jsonSchema.set(SCHEMA_KEY, properties);
+ final MediaTypeObject jsonSchema = new MediaTypeObject.Builder()
+ .schema(new Schema.Builder()
+ .properties(properties)
+ .build())
+ .build();
+ final Map<String, MediaTypeObject> content;
if (summary != null && summary.contains(HttpMethod.PATCH)) {
- content.set("application/yang-data+json", jsonSchema);
- content.set("application/yang-data+xml", buildMimeTypeValue(defName));
+ content = Map.of("application/yang-data+json", jsonSchema,
+ "application/yang-data+xml", buildMediaTypeObject(defName));
} else {
- content.set(MediaType.APPLICATION_JSON, jsonSchema);
- content.set(MediaType.APPLICATION_XML, buildMimeTypeValue(defName));
+ content = Map.of(MediaType.APPLICATION_JSON, jsonSchema,
+ MediaType.APPLICATION_XML, buildMediaTypeObject(defName));
}
- payload.set(CONTENT_KEY, content);
- payload.put(DESCRIPTION_KEY, description);
- return payload;
+ return content;
}
- private static ObjectNode buildRefSchema(final String defName) {
- final ObjectNode schema = JsonNodeFactory.instance.objectNode();
- schema.put(REF_KEY, COMPONENTS_PREFIX + defName);
- return schema;
+ private static Schema buildRefSchema(final String defName) {
+ return new Schema.Builder()
+ .ref(COMPONENTS_PREFIX + defName)
+ .build();
}
- private static ObjectNode buildMimeTypeValue(final String defName) {
- final ObjectNode mimeTypeValue = JsonNodeFactory.instance.objectNode();
- mimeTypeValue.set(SCHEMA_KEY, buildRefSchema(defName));
- return mimeTypeValue;
+ private static MediaTypeObject buildMediaTypeObject(final String defName) {
+ return new MediaTypeObject.Builder()
+ .schema(buildRefSchema(defName))
+ .build();
}
- private static ObjectNode buildResponse(final String description) {
- final ObjectNode response = JsonNodeFactory.instance.objectNode();
- response.put(DESCRIPTION_KEY, description);
- return response;
+ private static ResponseObject buildResponse(final String description) {
+ return new ResponseObject.Builder()
+ .description(description)
+ .build();
}
- private static ObjectNode buildResponse(final String description, final ObjectNode schema) {
- final ObjectNode response = JsonNodeFactory.instance.objectNode();
- final ObjectNode content = JsonNodeFactory.instance.objectNode();
- final ObjectNode body = JsonNodeFactory.instance.objectNode();
+ private static ResponseObject buildResponse(final String description, final Schema schema) {
+ final MediaTypeObject body = new MediaTypeObject.Builder()
+ .schema(schema)
+ .build();
+ final Map<String, MediaTypeObject> content = new HashMap<>();
for (final String mimeType : MIME_TYPES) {
- content.set(mimeType, body);
+ content.put(mimeType, body);
}
- body.set(SCHEMA_KEY, schema);
- response.set(CONTENT_KEY, content);
- response.put(DESCRIPTION_KEY, description);
- return response;
+ return new ResponseObject.Builder()
+ .content(content)
+ .description(description)
+ .build();
}
private static DataSchemaNode getListOrContainerChildNode(final DataSchemaNode node) {
import static org.opendaylight.restconf.openapi.impl.BaseYangOpenApiGenerator.filterByRange;
import static org.opendaylight.restconf.openapi.impl.BaseYangOpenApiGenerator.getSortedModules;
import static org.opendaylight.restconf.openapi.impl.OpenApiServiceImpl.DEFAULT_PAGESIZE;
-import static org.opendaylight.restconf.openapi.model.builder.OperationBuilder.DESCRIPTION_KEY;
import static org.opendaylight.restconf.openapi.model.builder.OperationBuilder.SUMMARY_TEMPLATE;
-import com.fasterxml.jackson.databind.node.JsonNodeFactory;
-import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.collect.Range;
import java.util.HashMap;
import java.util.List;
import org.opendaylight.restconf.openapi.model.OpenApiObject;
import org.opendaylight.restconf.openapi.model.Operation;
import org.opendaylight.restconf.openapi.model.Path;
+import org.opendaylight.restconf.openapi.model.ResponseObject;
import org.opendaylight.restconf.openapi.model.Schema;
import org.opendaylight.restconf.openapi.model.Server;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
final String deviceName) {
final String summary = SUMMARY_TEMPLATE.formatted(HttpMethod.GET, deviceName, "datastore", resourceType);
final List<String> tags = List.of(deviceName + " GET root");
- final ObjectNode okResponse = JsonNodeFactory.instance.objectNode();
- okResponse.put(DESCRIPTION_KEY, Response.Status.OK.getReasonPhrase());
- final ObjectNode responses = JsonNodeFactory.instance.objectNode();
- responses.set(String.valueOf(Response.Status.OK.getStatusCode()), okResponse);
+ final ResponseObject okResponse = new ResponseObject.Builder()
+ .description(Response.Status.OK.getReasonPhrase())
+ .build();
return new Operation.Builder()
.tags(tags)
- .responses(responses)
+ .responses(Map.of(String.valueOf(Response.Status.OK.getStatusCode()), okResponse))
.description(description)
.summary(summary)
.build();
}
private static String getSchemaPutOperationModuleName(final Operation put) {
- final var parentName = put.requestBody().path("content").path("application/json").path("schema")
- .path("properties").properties().iterator().next().getKey();
+ final var parentName = put.requestBody().content().get("application/json").schema().properties()
+ .keySet().iterator().next();
final var doubleDotsIndex = parentName.indexOf(':');
if (doubleDotsIndex >= 0 && doubleDotsIndex < parentName.length() - 1) {
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
-import com.fasterxml.jackson.databind.JsonNode;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
for (final var path : paths.values()) {
if (path.get() != null) {
final var responses = path.get().responses();
- final var response = responses.elements().next();
- final var content = response.get("content");
+ final var response = responses.values().iterator().next();
+ final var content = response.content();
// In case of 200 no content
if (content != null) {
- verifyOperationHaveCorrectXmlReference(content.get("application/xml").get("schema"));
- verifyOperationHaveCorrectJsonReference(content.get("application/json").get("schema"));
+ verifyOperationHaveCorrectXmlReference(content.get("application/xml").schema());
+ verifyOperationHaveCorrectJsonReference(content.get("application/json").schema());
}
}
if (path.put() != null) {
final var responses = path.put().requestBody();
- final var content = responses.get("content");
- verifyOperationHaveCorrectXmlReference(content.get("application/xml").get("schema"));
- verifyOperationHaveCorrectJsonReference(content.get("application/json").get("schema"));
+ final var content = responses.content();
+ verifyOperationHaveCorrectXmlReference(content.get("application/xml").schema());
+ verifyOperationHaveCorrectJsonReference(content.get("application/json").schema());
}
if (path.post() != null) {
final var responses = path.post().requestBody();
- final var content = responses.get("content");
- verifyOperationHaveCorrectXmlReference(content.get("application/xml").get("schema"));
- verifyOperationHaveCorrectJsonReference(content.get("application/json").get("schema"));
+ final var content = responses.content();
+ verifyOperationHaveCorrectXmlReference(content.get("application/xml").schema());
+ verifyOperationHaveCorrectJsonReference(content.get("application/json").schema());
}
if (path.patch() != null) {
final var responses = path.patch().requestBody();
- final var content = responses.get("content");
- verifyOperationHaveCorrectXmlReference(content.get("application/yang-data+xml").get("schema"));
- verifyOperationHaveCorrectJsonReference(content.get("application/yang-data+json").get("schema"));
+ final var content = responses.content();
+ verifyOperationHaveCorrectXmlReference(content.get("application/yang-data+xml").schema());
+ verifyOperationHaveCorrectJsonReference(content.get("application/yang-data+json").schema());
}
}
}
assertEquals(Set.of("ca-output"), actualProperties);
}
- private static void verifyOperationHaveCorrectXmlReference(final JsonNode schema) {
- final var ref = schema.get("$ref");
+ private static void verifyOperationHaveCorrectXmlReference(final Schema schema) {
+ final var refValue = schema.ref();
// In case of a POST RPC with a direct input body and no reference value
- if (ref != null) {
- final var refValue = ref.textValue();
+ if (refValue != null) {
final var schemaElement = refValue.substring(refValue.lastIndexOf("/") + 1);
assertTrue("Reference [" + refValue + "] not found in EXPECTED Schemas",
EXPECTED_SCHEMAS.contains(schemaElement));
} else {
- final var type = schema.get("type");
+ final var type = schema.type();
assertNotNull(type);
- assertEquals("object", type.asText());
+ assertEquals("object", type);
}
}
- private static void verifyOperationHaveCorrectJsonReference(final JsonNode schema) {
- final var properties = schema.findPath("properties");
+ private static void verifyOperationHaveCorrectJsonReference(final Schema schema) {
+ final var properties = schema.properties();
final String refValue;
- if (!properties.isMissingNode()) {
- final var node = properties.elements().next();
- final var type = node.path("type");
- if (type.isMissingNode()) {
- refValue = node.path("$ref").asText();
- } else if (type.asText().equals("array")) {
- refValue = node.path("items").path("$ref").asText();
+ if (properties != null) {
+ final var node = properties.values().iterator().next();
+ final var type = node.type();
+ if (type == null) {
+ refValue = node.ref();
+ } else if (type.equals("array")) {
+ refValue = node.items().ref();
} else {
- assertEquals("object", type.asText());
+ assertEquals("object", type);
return;
}
} else {
- refValue = schema.path("$ref").asText();
+ refValue = schema.ref();
}
final var schemaElement = refValue.substring(refValue.lastIndexOf("/") + 1);
assertTrue("Reference [" + refValue + "] not found in EXPECTED Schemas",
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
-import java.util.Collection;
import java.util.List;
import java.util.Optional;
import javax.ws.rs.core.UriInfo;
import org.opendaylight.mdsal.dom.api.DOMMountPointService;
import org.opendaylight.mdsal.dom.api.DOMSchemaService;
import org.opendaylight.restconf.openapi.impl.MountPointOpenApiGeneratorRFC8040;
+import org.opendaylight.restconf.openapi.model.MediaTypeObject;
import org.opendaylight.restconf.openapi.model.OpenApiObject;
import org.opendaylight.restconf.openapi.model.Operation;
+import org.opendaylight.restconf.openapi.model.Schema;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
* @return name of the schema used for operation
*/
private static String extractSchemaName(final Operation operation) {
- final var schemas = operation.requestBody().path("content").findValues("schema");
// Find distinct schema refs
- final var references = schemas.stream().map(s -> s.findValues("$ref"))
- .flatMap(Collection::stream).distinct().toList();
+ final var references = operation.requestBody().content().values().stream()
+ .map(MediaTypeObject::schema)
+ .map(SchemaObjectsTest::getRef)
+ .distinct()
+ .toList();
// Assert all schema refs are same
assertEquals("Inconsistent schemas for operation: " + operation.summary(), 1, references.size());
- return references.get(0).textValue().replaceAll("#/components/schemas/", "");
+ return references.get(0).replaceAll("#/components/schemas/", "");
+ }
+
+ private static String getRef(final Schema schema) {
+ final String ref;
+ if (schema.ref() != null) {
+ ref = schema.ref();
+ } else {
+ final var properties = schema.properties();
+ if (properties != null && !properties.isEmpty()) {
+ final var property = schema.properties().values().iterator().next();
+ if (property.type().equals("array")) {
+ ref = property.items().ref();
+ } else {
+ ref = property.ref();
+ }
+ } else {
+ ref = null;
+ }
+ }
+ return ref;
}
}
import static org.opendaylight.restconf.openapi.impl.BaseYangOpenApiGenerator.BASIC_AUTH_NAME;
import static org.opendaylight.restconf.openapi.model.builder.OperationBuilder.COMPONENTS_PREFIX;
-import com.fasterxml.jackson.databind.JsonNode;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import org.junit.Test;
import org.opendaylight.mdsal.dom.api.DOMSchemaService;
import org.opendaylight.restconf.openapi.DocGenTestHelper;
+import org.opendaylight.restconf.openapi.model.MediaTypeObject;
import org.opendaylight.restconf.openapi.model.OpenApiObject;
import org.opendaylight.restconf.openapi.model.Operation;
import org.opendaylight.restconf.openapi.model.Path;
final var jsonNodeCancelToast = doc.paths().get("/rests/operations/toaster2:cancel-toast");
assertNull(jsonNodeCancelToast.get());
// Test RPC with empty input
- final var postContent = jsonNodeCancelToast.post().requestBody().get("content");
- final var jsonSchema = postContent.get("application/json").get("schema");
- assertNull(jsonSchema.get("$ref"));
- assertEquals(2, jsonSchema.size());
- final var xmlSchema = postContent.get("application/xml").get("schema");
- assertNull(xmlSchema.get("$ref"));
- assertEquals(2, xmlSchema.size());
+ final var postContent = jsonNodeCancelToast.post().requestBody().content();
+ final var jsonSchema = postContent.get("application/json").schema();
+ assertNull(jsonSchema.ref());
+ final var xmlSchema = postContent.get("application/xml").schema();
+ assertNull(xmlSchema.ref());
// Test `components/schemas` objects
final var definitions = doc.components().schemas();
*/
private static void verifyPostDataRequestRef(final Operation operation, final String expectedJsonRef,
final String expectedXmlRef) {
- final JsonNode postContent;
+ final Map<String, MediaTypeObject> postContent;
if (operation.requestBody() != null) {
- postContent = operation.requestBody().get("content");
+ postContent = operation.requestBody().content();
} else {
- postContent = operation.responses().get("200").get("content");
+ postContent = operation.responses().get("200").content();
}
assertNotNull(postContent);
- final var postJsonRef = postContent.get("application/json").get("schema").get("$ref");
+ final var postJsonRef = postContent.get("application/json").schema().ref();
assertNotNull(postJsonRef);
- assertEquals(expectedJsonRef, postJsonRef.textValue());
- final var postXmlRef = postContent.get("application/xml").get("schema").get("$ref");
+ assertEquals(expectedJsonRef, postJsonRef);
+ final var postXmlRef = postContent.get("application/xml").schema().ref();
assertNotNull(postXmlRef);
- assertEquals(expectedXmlRef, postXmlRef.textValue());
+ assertEquals(expectedXmlRef, postXmlRef);
}
private static void verifyRequestRef(final Operation operation, final String expectedRef, final String nodeType) {
- final JsonNode postContent;
+ final Map<String, MediaTypeObject> postContent;
if (operation.requestBody() != null) {
- postContent = operation.requestBody().path("content");
+ postContent = operation.requestBody().content();
} else {
- postContent = operation.responses().path("200").path("content");
+ postContent = operation.responses().get("200").content();
}
assertNotNull(postContent);
final String postJsonRef;
if (nodeType.equals(CONTAINER)) {
- postJsonRef = postContent.path("application/json").path("schema").path("properties").elements().next()
- .path("$ref").textValue();
+ postJsonRef = postContent.get("application/json").schema().properties().values().iterator().next().ref();
} else {
- postJsonRef = postContent.path("application/json").path("schema").path("properties").elements().next()
- .path("items").path("$ref").textValue();
+ postJsonRef = postContent.get("application/json").schema().properties().values().iterator().next().items()
+ .ref();
}
assertNotNull(postJsonRef);
assertEquals(expectedRef, postJsonRef);
- final var postXmlRef = postContent.path("application/xml").path("schema").path("$ref");
+ final var postXmlRef = postContent.get("application/xml").schema().ref();
assertNotNull(postXmlRef);
- assertEquals(expectedRef, postXmlRef.textValue());
+ assertEquals(expectedRef, postXmlRef);
}
private static void verifyThatOthersNodeDoesNotHaveRequiredField(final List<String> expected,
final var references = new HashSet<String>();
final var get = path.get();
if (get != null) {
- references.addAll(schemaRefFromContent(get.responses().path("200").path("content")));
+ references.addAll(schemaRefFromContent(get.responses().get("200").content()));
}
final var post = path.post();
if (post != null) {
- references.addAll(schemaRefFromContent(post.requestBody().path("content")));
+ references.addAll(schemaRefFromContent(post.requestBody().content()));
}
final var put = path.put();
if (put != null) {
- references.addAll(schemaRefFromContent(put.requestBody().path("content")));
+ references.addAll(schemaRefFromContent(put.requestBody().content()));
}
final var patch = path.patch();
if (patch != null) {
- references.addAll(schemaRefFromContent(patch.requestBody().path("content")));
+ references.addAll(schemaRefFromContent(patch.requestBody().content()));
}
return references;
}
* @param content the element identified with key "content"
* @return the set of referenced schemas
*/
- private static Set<String> schemaRefFromContent(final JsonNode content) {
+ private static Set<String> schemaRefFromContent(final Map<String, MediaTypeObject> content) {
final HashSet<String> refs = new HashSet<>();
- content.fieldNames().forEachRemaining(mediaType -> {
- final JsonNode schema = content.path(mediaType).path("schema");
- final JsonNode props = schema.path("properties");
- final JsonNode nameNode = props.isMissingNode() ? props : props.elements().next().path("items");
- final JsonNode ref;
- if (props.isMissingNode()) {
+ content.values().forEach(mediaType -> {
+ final var schema = mediaType.schema();
+ final var props = mediaType.schema().properties();
+ final String ref;
+ if (props == null) {
// either there is no node with the key "properties", try to find immediate child of schema
- ref = schema.path("$ref");
- } else if (nameNode.path("items").isMissingNode()) {
+ ref = schema.ref();
+ } else if (props.values().iterator().next().items() == null) {
// or the "properties" is defined and under that we didn't find the "items" node
- // try to get "$ref" as immediate child under nameNode
- ref = nameNode.path("$ref");
+ // try to get "$ref" as immediate child under properties
+ ref = props.values().iterator().next().ref();
} else {
// or the "items" node is defined, in which case we try to get the "$ref" from this node
- ref = nameNode.path("items").path("$ref");
+ ref = props.values().iterator().next().items().ref();
}
- if (ref != null && !ref.isMissingNode()) {
- refs.add(ref.asText().replaceFirst(COMPONENTS_PREFIX, ""));
+ if (ref != null) {
+ refs.add(ref.replaceFirst(COMPONENTS_PREFIX, ""));
}
});
return refs;
}
}
}""";
- private static final String CONTENT_KEY = "content";
- private static final String SCHEMA_KEY = "schema";
private static OpenApiObject containerDoc;
private static OpenApiObject listDoc;
final var path1 = "/rests/data/container-test:cont";
assertTrue(containerDoc.paths().containsKey(path1));
final var jsonRef1 = getJsonRef(containerDoc, path1);
- assertEquals("{\"cont1\":{\"$ref\":\"#/components/schemas/container-test_cont_cont1\"}}",
- jsonRef1);
+ assertEquals("#/components/schemas/container-test_cont_cont1", jsonRef1);
final var xmlRef1 = getXmlRef(containerDoc, path1);
assertEquals("#/components/schemas/container-test_cont_cont1", xmlRef1);
final var path2 = "/rests/data/container-test:cont/cont1";
assertTrue(containerDoc.paths().containsKey(path2));
final var jsonRef2 = getJsonRef(containerDoc, path2);
- assertEquals("{\"list4\":{\"type\":\"array\",\"items\":{\"$ref\":\""
- + "#/components/schemas/container-test_cont_cont1_list4\"}}}", jsonRef2);
+ assertEquals("#/components/schemas/container-test_cont_cont1_list4", jsonRef2);
final var xmlRef2 = getXmlRef(containerDoc, path2);
assertEquals("#/components/schemas/container-test_cont_cont1_list4", xmlRef2);
final var path4 = "/rests/data/container-test:cont/cont1/list4={key4}/cont2";
assertTrue(containerDoc.paths().containsKey(path4));
final var jsonRef4 = getJsonRef(containerDoc, path4);
- assertEquals("{\"list5\":{\"type\":\"array\",\"items\":{\"$ref\":\""
- + "#/components/schemas/container-test_cont_cont1_list4_cont2_list5\"}}}", jsonRef4);
+ assertEquals("#/components/schemas/container-test_cont_cont1_list4_cont2_list5", jsonRef4);
final var xmlRef4 = getXmlRef(containerDoc, path4);
assertEquals("#/components/schemas/container-test_cont_cont1_list4_cont2_list5", xmlRef4);
}
final var path1 = "/rests/data/list-test:cont";
assertTrue(listDoc.paths().containsKey(path1));
final var jsonRef1 = getJsonRef(listDoc, path1);
- assertEquals("{\"list1\":{\"type\":\"array\",\"items\":{\"$ref\":\""
- + "#/components/schemas/list-test_cont_list1\"}}}", jsonRef1);
+ assertEquals("#/components/schemas/list-test_cont_list1", jsonRef1);
final var xmlRef1 = getXmlRef(listDoc, path1);
assertEquals("#/components/schemas/list-test_cont_list1", xmlRef1);
}
private static String getJsonRef(final OpenApiObject openApiObject, final String path) {
- return openApiObject.paths().get(path).post().requestBody().get(CONTENT_KEY).get("application/json")
- .get(SCHEMA_KEY).get("properties").toString();
+ final var property = openApiObject.paths().get(path).post().requestBody().content().get("application/json")
+ .schema().properties().values().iterator().next();
+ if (property.type().equals("object")) {
+ return property.ref();
+ } else {
+ return property.items().ref();
+ }
}
private static String getXmlRef(final OpenApiObject openApiObject, final String path) {
- return openApiObject.paths().get(path).post().requestBody().get(CONTENT_KEY).get(
- "application/xml").get(SCHEMA_KEY).get("$ref").asText();
+ return openApiObject.paths().get(path).post().requestBody().content().get(
+ "application/xml").schema().ref();
}
}