3ca5c39aff210cdd7de0e1052879330665102cc7
[netconf.git] / restconf / restconf-openapi / src / main / java / org / opendaylight / restconf / openapi / model / SchemaEntity.java
1 /*
2  * Copyright (c) 2023 PANTHEON.tech, s.r.o. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.restconf.openapi.model;
9
10 import static java.util.Objects.requireNonNull;
11 import static java.util.Objects.requireNonNullElse;
12 import static org.opendaylight.restconf.openapi.model.PropertyEntity.isSchemaNodeMandatory;
13
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.SchemaNode;
28 import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
29
30 /**
31  * Archetype for a Schema.
32  */
33 public final class SchemaEntity extends OpenApiEntity {
34     private final @NonNull SchemaNode value;
35     private final @NonNull String title;
36     private final @NonNull String discriminator;
37     private final @NonNull String type;
38     private final @NonNull SchemaInferenceStack stack;
39     private final boolean isParentConfig;
40     private final SchemasStream.EntityType entityType;
41     private final @NonNull String parentName;
42     private final @NonNull DefinitionNames definitionNames;
43
44     public SchemaEntity(final @NonNull SchemaNode value, final @NonNull String title, final String discriminator,
45             @NonNull final String type, @NonNull final SchemaInferenceStack context, final String parentName,
46             final boolean isParentConfig, @NonNull final DefinitionNames definitionNames,
47             final SchemasStream.EntityType entityType) {
48         this.value = requireNonNull(value);
49         this.title = requireNonNull(title);
50         this.type = requireNonNull(type);
51         this.stack = requireNonNull(context.copy());
52         this.parentName = requireNonNull(parentName);
53         this.isParentConfig = isParentConfig;
54         this.definitionNames = definitionNames;
55         this.entityType = entityType;
56         this.discriminator = requireNonNullElse(discriminator, "");
57     }
58
59     @Override
60     public void generate(final @NonNull JsonGenerator generator) throws IOException {
61         generator.writeObjectFieldStart(title() + discriminator);
62         generator.writeStringField("title", title());
63         generator.writeStringField("type", type());
64         final var description = description();
65         if (description != null) {
66             generator.writeStringField("description", description);
67         }
68         generateProperties(generator);
69         generateXml(generator);
70         generator.writeEndObject();
71     }
72
73     private @NonNull String title() {
74         return title;
75     }
76
77     private @NonNull String type() {
78         return type;
79     }
80
81     private @Nullable String description() {
82         return value.getDescription().orElse(null);
83     }
84
85     private void generateRequired(final @NonNull JsonGenerator generator, final List<String> required)
86             throws IOException {
87         if (!required.isEmpty()) {
88             generator.writeArrayFieldStart("required");
89             for (final var req : required) {
90                 generator.writeString(req);
91             }
92             generator.writeEndArray();
93         }
94     }
95
96     private void generateProperties(final @NonNull JsonGenerator generator) throws IOException {
97         final var required = new ArrayList<String>();
98         generator.writeObjectFieldStart("properties");
99         stack.enterSchemaTree(value.getQName());
100         switch (entityType) {
101             case RPC:
102                 for (final var childNode : ((ContainerLike) value).getChildNodes()) {
103                     new PropertyEntity(childNode, generator, stack, required, parentName, isParentConfig,
104                         definitionNames);
105                 }
106                 break;
107             default:
108                 final var childNodes = new HashMap<String, DataSchemaNode>();
109                 for (final var childNode : ((DataNodeContainer) value).getChildNodes()) {
110                     childNodes.put(childNode.getQName().getLocalName(), childNode);
111                 }
112                 for (final var childNode : childNodes.values()) {
113                     if (shouldBeAddedAsProperty(childNode)) {
114                         new PropertyEntity(childNode, generator, stack, required, parentName + "_"
115                             + value.getQName().getLocalName(), ((DataSchemaNode) value).isConfiguration(),
116                             definitionNames);
117                     }
118                 }
119         }
120         stack.exit();
121         generator.writeEndObject();
122         generateRequired(generator, required);
123     }
124
125     private boolean shouldBeAddedAsProperty(final DataSchemaNode childNode) {
126         if (childNode instanceof ContainerSchemaNode) {
127             return childNode.isConfiguration() || isSchemaNodeMandatory(childNode)
128                 || !((DataSchemaNode) value).isConfiguration();
129         }
130         return childNode.isConfiguration() || !((DataSchemaNode) value).isConfiguration();
131     }
132
133     private void generateXml(final @NonNull JsonGenerator generator) throws IOException {
134         generator.writeObjectFieldStart("xml");
135         generator.writeStringField("name", value.getQName().getLocalName());
136         generator.writeStringField("namespace", value.getQName().getNamespace().toString());
137         generator.writeEndObject();
138     }
139 }