WIP: Add OpenApi{Entity,BodyWriter} 49/107149/20
authorRobert Varga <robert.varga@pantheon.tech>
Mon, 31 Jul 2023 13:48:03 +0000 (15:48 +0200)
committerIvan Hrasko <ivan.hrasko@pantheon.tech>
Fri, 8 Dec 2023 13:52:11 +0000 (13:52 +0000)
With JAX-RS we can defer generation to when the response is created,
via indirection through a MessageBodyWriter.

This provides the basic wiring to do that.

JIRA: NETCONF-938
Change-Id: I7451cc49ac1cceddfde1ddf4bb1052a9888c1886
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
Signed-off-by: Ivan Hrasko <ivan.hrasko@pantheon.tech>
restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/jaxrs/OpenApiBodyWriter.java [new file with mode: 0644]
restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/model/OpenApiEntity.java [new file with mode: 0644]
restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/model/SchemaEntity.java [new file with mode: 0644]

diff --git a/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/jaxrs/OpenApiBodyWriter.java b/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/jaxrs/OpenApiBodyWriter.java
new file mode 100644 (file)
index 0000000..93eb6fa
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * 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.jaxrs;
+
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.core.JsonFactoryBuilder;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.MessageBodyWriter;
+import javax.ws.rs.ext.Provider;
+import org.opendaylight.restconf.openapi.model.OpenApiEntity;
+
+/**
+ * A {@link MessageBodyWriter} capable of turning {@link OpenApiEntity} objects into JSON body.
+ */
+@Provider
+@Produces(MediaType.APPLICATION_JSON)
+public final class OpenApiBodyWriter implements MessageBodyWriter<OpenApiEntity> {
+    private final JsonFactory factory = new JsonFactoryBuilder().build();
+
+    @Override
+    public boolean isWriteable(final Class<?> type, final Type genericType, final Annotation[] annotations,
+            final MediaType mediaType) {
+        return OpenApiEntity.class.isAssignableFrom(type);
+    }
+
+    @Override
+    public void writeTo(final OpenApiEntity entity, final Class<?> type, final Type genericType,
+            final Annotation[] annotations, final MediaType mediaType, final MultivaluedMap<String, Object> httpHeaders,
+            final OutputStream entityStream) throws IOException {
+        try (var generator = factory.createGenerator(entityStream)) {
+            entity.generate(generator);
+        }
+    }
+}
diff --git a/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/model/OpenApiEntity.java b/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/model/OpenApiEntity.java
new file mode 100644 (file)
index 0000000..c4050b0
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * 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.core.JsonGenerator;
+import java.io.IOException;
+import org.eclipse.jdt.annotation.NonNull;
+
+/**
+ * A response entity for complex generated type.
+ */
+public abstract sealed class OpenApiEntity permits SchemaEntity {
+    /**
+     * Generate JSON events into specified generator.
+     *
+     * @param generator JsonGenerator to emit events to
+     * @throws IOException when an error occurs
+     */
+    public abstract void generate(@NonNull JsonGenerator generator) throws IOException;
+}
diff --git a/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/model/SchemaEntity.java b/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/model/SchemaEntity.java
new file mode 100644 (file)
index 0000000..6a155dc
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * 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 static java.util.Objects.requireNonNull;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import java.io.IOException;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+
+/**
+ * Archetype for a Schema.
+ */
+public final class SchemaEntity extends OpenApiEntity {
+    private final @NonNull String title;
+    private final @NonNull String type;
+
+    public SchemaEntity(final @NonNull String title, final @NonNull String type) {
+        this.title = requireNonNull(title);
+        this.type = requireNonNull(type);
+    }
+
+    @Override
+    public void generate(final @NonNull JsonGenerator generator) throws IOException {
+        generator.writeObjectFieldStart(title());
+        generator.writeStringField("title", title());
+        generator.writeStringField("type", type());
+        final var description = description();
+        if (description != null) {
+            generator.writeStringField("description", description);
+        }
+        final var reference = reference();
+        if (reference != null) {
+            generator.writeStringField("$ref", reference);
+        }
+        generateEnum(generator);
+        generateRequired(generator);
+        generateDiscriminator(generator);
+        generateExamples(generator);
+        generateExternalDocs(generator);
+        generateProperties(generator);
+        generateXml(generator);
+        generator.writeEndObject();
+    }
+
+    private @NonNull String title() {
+        return title;
+    }
+
+    private @NonNull String type() {
+        return type;
+    }
+
+    private @Nullable String description() {
+        return null;
+    }
+
+    private @Nullable String reference() {
+        return null;
+    }
+
+    private void generateEnum(final @NonNull JsonGenerator generator) throws IOException {
+        // No-op
+    }
+
+    private void generateRequired(final @NonNull JsonGenerator generator) throws IOException {
+        // No-op
+    }
+
+    private void generateDiscriminator(final @NonNull JsonGenerator generator) throws IOException {
+        // No-op
+    }
+
+    private void generateExamples(final @NonNull JsonGenerator generator) throws IOException {
+        // No-op
+    }
+
+    private void generateExternalDocs(final @NonNull JsonGenerator generator) throws IOException {
+        // No-op
+    }
+
+    private void generateProperties(final @NonNull JsonGenerator generator) throws IOException {
+        // No-op
+    }
+
+    private void generateXml(final @NonNull JsonGenerator generator) throws IOException {
+        // No-op
+    }
+}