2 * Copyright (c) 2023 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
8 package org.opendaylight.restconf.openapi.model;
10 import static java.util.Objects.requireNonNull;
11 import static javax.ws.rs.core.Response.Status.CREATED;
12 import static javax.ws.rs.core.Response.Status.NO_CONTENT;
13 import static javax.ws.rs.core.Response.Status.OK;
15 import com.fasterxml.jackson.core.JsonGenerator;
16 import java.io.IOException;
17 import java.util.List;
18 import javax.ws.rs.HttpMethod;
19 import javax.ws.rs.core.MediaType;
20 import org.eclipse.jdt.annotation.NonNull;
21 import org.eclipse.jdt.annotation.Nullable;
22 import org.opendaylight.yangtools.yang.model.api.ActionDefinition;
23 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
24 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
25 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
26 import org.opendaylight.yangtools.yang.model.api.DocumentedNode;
27 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
28 import org.opendaylight.yangtools.yang.model.api.Module;
29 import org.opendaylight.yangtools.yang.model.api.OperationDefinition;
30 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
32 public final class PostEntity extends OperationEntity {
33 private static final String INPUT_SUFFIX = "_input";
34 private static final String INPUT_KEY = "input";
35 private static final String POST_DESCRIPTION = """
38 In example payload, you can see only the first data node child of the resource to be created, following the
39 guidelines of RFC 8040, which allows us to create only one resource in POST request.
42 private final @Nullable DocumentedNode parentNode;
43 private final @NonNull List<SchemaNode> parentNodes;
45 public PostEntity(final @NonNull SchemaNode schema, final @NonNull String deviceName,
46 final @NonNull String moduleName, final @NonNull List<ParameterEntity> parameters,
47 final @NonNull String refPath, final @Nullable DocumentedNode parentNode,
48 final @NonNull List<SchemaNode> parentNodes) {
49 super(requireNonNull(schema), deviceName, moduleName, requireNonNull(parameters), requireNonNull(refPath));
50 this.parentNode = parentNode;
51 this.parentNodes = requireNonNull(parentNodes);
54 protected @NonNull String operation() {
58 @NonNull String summary() {
59 if (parentNode instanceof Module) {
60 return SUMMARY_TEMPLATE.formatted(HttpMethod.POST, deviceName(), moduleName(), moduleName());
62 if (parentNode != null && !(schema() instanceof OperationDefinition)) {
63 return SUMMARY_TEMPLATE.formatted(HttpMethod.POST, deviceName(), moduleName(),
64 ((DataSchemaNode) parentNode).getQName().getLocalName());
66 return SUMMARY_TEMPLATE.formatted(HttpMethod.POST, deviceName(), moduleName(), nodeName());
70 void generateResponses(final @NonNull JsonGenerator generator) throws IOException {
71 generator.writeObjectFieldStart(RESPONSES);
72 if (schema() instanceof OperationDefinition rpc) {
73 final var output = rpc.getOutput();
74 final var operationName = rpc.getQName().getLocalName();
75 if (!output.getChildNodes().isEmpty()) {
76 final var ref = processOperationsRef(rpc, operationName, "_output");
77 generator.writeObjectFieldStart(String.valueOf(OK.getStatusCode()));
78 generator.writeStringField(DESCRIPTION, String.format("RPC %s success", operationName));
80 generator.writeObjectFieldStart(CONTENT);
81 generateMediaTypeSchemaRef(generator, MediaType.APPLICATION_JSON, ref);
82 generateMediaTypeSchemaRef(generator, MediaType.APPLICATION_XML, ref);
83 generator.writeEndObject();
85 generator.writeEndObject();
88 generator.writeObjectFieldStart(String.valueOf(NO_CONTENT.getStatusCode()));
89 generator.writeStringField(DESCRIPTION, String.format("RPC %s success", operationName));
90 generator.writeEndObject();
94 generator.writeObjectFieldStart(String.valueOf(CREATED.getStatusCode()));
95 generator.writeStringField(DESCRIPTION, "Created");
96 generator.writeEndObject();
98 generator.writeEndObject();
102 void generateRequestBody(final @NonNull JsonGenerator generator) throws IOException {
103 generator.writeObjectFieldStart(REQUEST_BODY);
104 if (schema() instanceof OperationDefinition rpc) {
105 final var input = rpc.getInput();
106 final var operationName = rpc.getQName().getLocalName();
107 generator.writeStringField(DESCRIPTION, operationName + INPUT_SUFFIX);
108 generator.writeObjectFieldStart(CONTENT);
109 if (!input.getChildNodes().isEmpty()) {
110 final var ref = processOperationsRef(rpc, operationName, INPUT_SUFFIX);
111 generator.writeObjectFieldStart(MediaType.APPLICATION_JSON);
112 generator.writeObjectFieldStart(SCHEMA);
113 generator.writeObjectFieldStart("properties");
114 generator.writeObjectFieldStart(INPUT_KEY);
115 generator.writeStringField("$ref", ref);
116 generator.writeStringField(TYPE, OBJECT);
117 generator.writeEndObject();
118 generator.writeEndObject();
119 generator.writeEndObject();
120 generator.writeEndObject();
121 generateMediaTypeSchemaRef(generator, MediaType.APPLICATION_XML, ref);
123 generator.writeObjectFieldStart(MediaType.APPLICATION_JSON);
124 generator.writeObjectFieldStart(SCHEMA);
126 generator.writeObjectFieldStart(PROPERTIES);
127 generator.writeObjectFieldStart(INPUT_KEY);
128 generator.writeStringField(TYPE, OBJECT);
129 generator.writeEndObject();
130 generator.writeEndObject();
132 generator.writeStringField(TYPE, OBJECT);
133 generator.writeEndObject();
134 generator.writeEndObject();
136 generator.writeObjectFieldStart(MediaType.APPLICATION_XML);
137 generator.writeObjectFieldStart(SCHEMA);
139 generator.writeObjectFieldStart("xml");
140 generator.writeStringField(NAME, INPUT_KEY);
141 generator.writeStringField("namespace", input.getQName().getNamespace().toString());
142 generator.writeEndObject();
144 generator.writeStringField(TYPE, OBJECT);
145 generator.writeEndObject();
146 generator.writeEndObject();
148 generator.writeEndObject();
150 generator.writeStringField(DESCRIPTION, nodeName());
151 generator.writeObjectFieldStart(CONTENT);
152 final var ref = COMPONENTS_PREFIX + moduleName() + "_" + refPath();
153 var childConfig = true;
154 if (schema() instanceof DataNodeContainer dataSchema) {
155 final var child = dataSchema.getChildNodes().stream()
156 .filter(n -> n instanceof ListSchemaNode || n instanceof ContainerSchemaNode)
157 .findFirst().orElse(null);
159 childConfig = child.isConfiguration();
162 if (parentNode == null && !childConfig) {
163 generateMediaTypeSchemaRef(generator, MediaType.APPLICATION_JSON, ref);
165 generator.writeObjectFieldStart(MediaType.APPLICATION_JSON);
166 generator.writeObjectFieldStart(SCHEMA);
168 generator.writeObjectFieldStart(PROPERTIES);
169 generator.writeObjectFieldStart(nodeName());
170 if (schema() instanceof ListSchemaNode) {
171 generator.writeStringField(TYPE, ARRAY);
172 generator.writeObjectFieldStart(ITEMS);
173 generator.writeStringField(REF, ref);
174 generator.writeStringField(TYPE, OBJECT);
175 generator.writeEndObject();
177 generator.writeStringField(REF, ref);
178 generator.writeStringField(TYPE, OBJECT);
180 generator.writeEndObject();
181 generator.writeEndObject();
182 generator.writeEndObject();
183 generator.writeEndObject();
185 generateMediaTypeSchemaRef(generator, MediaType.APPLICATION_XML, ref);
186 generator.writeEndObject();
188 generator.writeEndObject();
192 public void generateBasics(@NonNull JsonGenerator generator) throws IOException {
193 final var description = description();
194 if (schema() instanceof OperationDefinition) {
195 generator.writeStringField(DESCRIPTION, description);
197 generator.writeStringField(DESCRIPTION, description + POST_DESCRIPTION);
199 generator.writeStringField(SUMMARY, summary());
203 @NonNull String description() {
204 if (parentNode != null && !(schema() instanceof OperationDefinition)) {
205 return parentNode.getDescription().orElse("");
207 return super.description();
211 private String processOperationsRef(final OperationDefinition def, final String operationName, final String suf) {
212 final var ref = new StringBuilder(COMPONENTS_PREFIX + moduleName() + "_");
213 if (def instanceof ActionDefinition) {
214 final boolean hasChildNodes = suf.equals(INPUT_SUFFIX) ? !def.getInput().getChildNodes().isEmpty()
215 : !def.getOutput().getChildNodes().isEmpty();
217 for (final SchemaNode node : parentNodes) {
218 ref.append(node.getQName().getLocalName()).append("_");
222 return ref.append(operationName).append(suf).toString();