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 java.util.Objects.requireNonNullElse;
12 import static org.opendaylight.restconf.openapi.model.PropertyEntity.isSchemaNodeMandatory;
14 import com.fasterxml.jackson.core.JsonGenerator;
15 import java.io.IOException;
16 import java.util.ArrayList;
17 import java.util.HashMap;
18 import java.util.List;
19 import org.eclipse.jdt.annotation.NonNull;
20 import org.eclipse.jdt.annotation.Nullable;
21 import org.opendaylight.restconf.openapi.impl.DefinitionNames;
22 import org.opendaylight.restconf.openapi.impl.SchemasStream;
23 import org.opendaylight.yangtools.yang.model.api.ContainerLike;
24 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
25 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
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.OutputSchemaNode;
29 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
30 import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
33 * Archetype for a Schema.
35 public final class SchemaEntity extends OpenApiEntity {
36 private final @NonNull SchemaNode value;
37 private final @NonNull String title;
38 private final @NonNull String discriminator;
39 private final @NonNull String type;
40 private final @NonNull SchemaInferenceStack stack;
41 private final boolean isParentConfig;
42 private final SchemasStream.EntityType entityType;
43 private final @NonNull String parentName;
44 private final @NonNull DefinitionNames definitionNames;
46 public SchemaEntity(final @NonNull SchemaNode value, final @NonNull String title, final String discriminator,
47 @NonNull final String type, @NonNull final SchemaInferenceStack context, final String parentName,
48 final boolean isParentConfig, @NonNull final DefinitionNames definitionNames,
49 final SchemasStream.EntityType entityType) {
50 this.value = requireNonNull(value);
51 this.title = requireNonNull(title);
52 this.type = requireNonNull(type);
53 this.stack = requireNonNull(context.copy());
54 this.parentName = requireNonNull(parentName);
55 this.isParentConfig = isParentConfig;
56 this.definitionNames = definitionNames;
57 this.entityType = entityType;
58 this.discriminator = requireNonNullElse(discriminator, "");
62 public void generate(final @NonNull JsonGenerator generator) throws IOException {
63 generator.writeObjectFieldStart(title() + discriminator);
64 generator.writeStringField("title", title());
65 generator.writeStringField("type", type());
66 final var description = description();
67 if (description != null) {
68 generator.writeStringField("description", description);
70 generateProperties(generator);
71 generateXml(generator);
72 generator.writeEndObject();
75 private @NonNull String title() {
79 private @NonNull String type() {
83 private @Nullable String description() {
84 // FIXME: Ensure the method returns null if the description is not available.
85 return value.getDescription()
86 .orElse(value instanceof InputSchemaNode || value instanceof OutputSchemaNode ? null : "");
89 private void generateRequired(final @NonNull JsonGenerator generator, final List<String> required)
91 if (!required.isEmpty()) {
92 generator.writeArrayFieldStart("required");
93 for (final var req : required) {
94 generator.writeString(req);
96 generator.writeEndArray();
100 private void generateProperties(final @NonNull JsonGenerator generator) throws IOException {
101 final var required = new ArrayList<String>();
102 generator.writeObjectFieldStart("properties");
103 stack.enterSchemaTree(value.getQName());
104 switch (entityType) {
106 for (final var childNode : ((ContainerLike) value).getChildNodes()) {
107 new PropertyEntity(childNode, generator, stack, required, parentName, isParentConfig,
112 final var childNodes = new HashMap<String, DataSchemaNode>();
113 for (final var childNode : ((DataNodeContainer) value).getChildNodes()) {
114 childNodes.put(childNode.getQName().getLocalName(), childNode);
116 for (final var childNode : childNodes.values()) {
117 if (shouldBeAddedAsProperty(childNode)) {
118 new PropertyEntity(childNode, generator, stack, required, parentName + "_"
119 + value.getQName().getLocalName(), ((DataSchemaNode) value).isConfiguration(),
125 generator.writeEndObject();
126 generateRequired(generator, required);
129 private boolean shouldBeAddedAsProperty(final DataSchemaNode childNode) {
130 if (childNode instanceof ContainerSchemaNode) {
131 return childNode.isConfiguration() || isSchemaNodeMandatory(childNode)
132 || !((DataSchemaNode) value).isConfiguration();
134 return childNode.isConfiguration() || !((DataSchemaNode) value).isConfiguration();
137 private void generateXml(final @NonNull JsonGenerator generator) throws IOException {
138 generator.writeObjectFieldStart("xml");
139 generator.writeStringField("name", value.getQName().getLocalName());
140 generator.writeStringField("namespace", value.getQName().getNamespace().toString());
141 generator.writeEndObject();