From 0ae7d6767f1203b7428dd5d1a5f68fd01d5e79d2 Mon Sep 17 00:00:00 2001 From: Ivan Hrasko Date: Tue, 16 Jan 2024 15:49:54 +0100 Subject: [PATCH] Use nio Channels in OpenAPI read Override read(byte[], int, int) method using nio Channels to speed up retrieval of documentation. JIRA: NETCONF-1234 Change-Id: I3bfc4110cfe828302a08f86756c4535077fe5c5c Signed-off-by: Ivan Hrasko Signed-off-by: Yaroslav Lastivka --- .../openapi/impl/ComponentsStream.java | 35 ++++++++++++++++++- .../restconf/openapi/impl/InfoStream.java | 9 ++++- .../openapi/impl/OpenApiInputStream.java | 30 +++++++++++++++- .../openapi/impl/OpenApiVersionStream.java | 9 ++++- .../restconf/openapi/impl/PathsStream.java | 9 ++++- .../restconf/openapi/impl/SchemaStream.java | 22 +++++++++++- .../restconf/openapi/impl/SchemasStream.java | 32 ++++++++++++++++- .../openapi/impl/SecuritySchemesStream.java | 10 +++++- .../restconf/openapi/impl/SecurityStream.java | 9 ++++- .../restconf/openapi/impl/ServersStream.java | 9 ++++- 10 files changed, 164 insertions(+), 10 deletions(-) diff --git a/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/impl/ComponentsStream.java b/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/impl/ComponentsStream.java index b3cbb31f19..5b97b7b52f 100644 --- a/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/impl/ComponentsStream.java +++ b/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/impl/ComponentsStream.java @@ -14,6 +14,9 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; +import java.nio.ByteBuffer; +import java.nio.channels.Channels; +import java.nio.channels.ReadableByteChannel; import java.nio.charset.StandardCharsets; import java.util.Iterator; import java.util.Map; @@ -36,6 +39,7 @@ public final class ComponentsStream extends InputStream { private boolean schemasWritten; private boolean securityWritten; private Reader reader; + private ReadableByteChannel channel; public ComponentsStream(final EffectiveModelContext context, final OpenApiBodyWriter writer, final JsonGenerator generator, final ByteArrayOutputStream stream, @@ -84,6 +88,35 @@ public final class ComponentsStream extends InputStream { @Override public int read(final byte[] array, final int off, final int len) throws IOException { - return super.read(array, off, len); + if (channel == null) { + generator.writeObjectFieldStart("components"); + generator.flush(); + channel = Channels.newChannel(new ByteArrayInputStream(stream.toByteArray())); + stream.reset(); + } + + var read = channel.read(ByteBuffer.wrap(array, off, len)); + while (read == -1) { + if (!schemasWritten) { + channel = Channels.newChannel(new SchemasStream(context, writer, generator, stream, iterator, + isForSingleModule)); + read = channel.read(ByteBuffer.wrap(array)); + schemasWritten = true; + continue; + } + if (!securityWritten) { + channel = Channels.newChannel(new SecuritySchemesStream(writer, Map.of(BASIC_AUTH_NAME, + OPEN_API_BASIC_AUTH))); + read = channel.read(ByteBuffer.wrap(array, off, len)); + securityWritten = true; + generator.writeEndObject(); + continue; + } + generator.flush(); + channel = Channels.newChannel(new ByteArrayInputStream(stream.toByteArray())); + stream.reset(); + return channel.read(ByteBuffer.wrap(array, off, len)); + } + return read; } } diff --git a/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/impl/InfoStream.java b/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/impl/InfoStream.java index e41129f9f4..50eac5752a 100644 --- a/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/impl/InfoStream.java +++ b/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/impl/InfoStream.java @@ -13,6 +13,9 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; +import java.nio.ByteBuffer; +import java.nio.channels.Channels; +import java.nio.channels.ReadableByteChannel; import java.nio.charset.StandardCharsets; import org.opendaylight.restconf.openapi.jaxrs.OpenApiBodyWriter; import org.opendaylight.restconf.openapi.model.InfoEntity; @@ -23,6 +26,7 @@ public final class InfoStream extends InputStream { private final OpenApiBodyWriter writer; private Reader reader; + private ReadableByteChannel channel; public InfoStream(final InfoEntity entity, final OpenApiBodyWriter writer) { this.entity = entity; @@ -40,7 +44,10 @@ public final class InfoStream extends InputStream { @Override public int read(final byte[] array, final int off, final int len) throws IOException { - return super.read(array, off, len); + if (channel == null) { + channel = Channels.newChannel(new ByteArrayInputStream(writeNextEntity(entity))); + } + return channel.read(ByteBuffer.wrap(array, off, len)); } private byte[] writeNextEntity(final OpenApiEntity next) throws IOException { diff --git a/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/impl/OpenApiInputStream.java b/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/impl/OpenApiInputStream.java index e39f21d288..6adcc7fa6e 100644 --- a/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/impl/OpenApiInputStream.java +++ b/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/impl/OpenApiInputStream.java @@ -16,6 +16,9 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; +import java.nio.ByteBuffer; +import java.nio.channels.Channels; +import java.nio.channels.ReadableByteChannel; import java.nio.charset.StandardCharsets; import java.util.ArrayDeque; import java.util.Collection; @@ -37,6 +40,7 @@ public final class OpenApiInputStream extends InputStream { private final Deque stack = new ArrayDeque<>(); private Reader reader; + private ReadableByteChannel channel; private boolean eof; @@ -87,6 +91,30 @@ public final class OpenApiInputStream extends InputStream { @Override public int read(final byte[] array, final int off, final int len) throws IOException { - return super.read(array, off, len); + if (eof) { + return -1; + } + if (channel == null) { + generator.writeStartObject(); + generator.flush(); + channel = Channels.newChannel(new ByteArrayInputStream(stream.toByteArray())); + stream.reset(); + } + + var read = channel.read(ByteBuffer.wrap(array, off, len)); + while (read == -1) { + if (stack.isEmpty()) { + generator.writeEndObject(); + generator.flush(); + channel = Channels.newChannel(new ByteArrayInputStream(stream.toByteArray())); + stream.reset(); + eof = true; + return channel.read(ByteBuffer.wrap(array, off, len)); + } + channel = Channels.newChannel(stack.pop()); + read = channel.read(ByteBuffer.wrap(array, off, len)); + } + + return read; } } diff --git a/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/impl/OpenApiVersionStream.java b/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/impl/OpenApiVersionStream.java index 0553d0e659..e412e54279 100644 --- a/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/impl/OpenApiVersionStream.java +++ b/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/impl/OpenApiVersionStream.java @@ -13,6 +13,9 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; +import java.nio.ByteBuffer; +import java.nio.channels.Channels; +import java.nio.channels.ReadableByteChannel; import java.nio.charset.StandardCharsets; import org.opendaylight.restconf.openapi.jaxrs.OpenApiBodyWriter; import org.opendaylight.restconf.openapi.model.OpenApiEntity; @@ -23,6 +26,7 @@ public final class OpenApiVersionStream extends InputStream { private final OpenApiBodyWriter writer; private Reader reader; + private ReadableByteChannel channel; public OpenApiVersionStream(final OpenApiVersionEntity entity, final OpenApiBodyWriter writer) { this.entity = entity; @@ -40,7 +44,10 @@ public final class OpenApiVersionStream extends InputStream { @Override public int read(final byte[] array, final int off, final int len) throws IOException { - return super.read(array, off, len); + if (channel == null) { + channel = Channels.newChannel(new ByteArrayInputStream(writeNextEntity(entity))); + } + return channel.read(ByteBuffer.wrap(array, off, len)); } private byte[] writeNextEntity(final OpenApiEntity next) throws IOException { diff --git a/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/impl/PathsStream.java b/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/impl/PathsStream.java index 2c72fc672e..01ed0346e8 100644 --- a/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/impl/PathsStream.java +++ b/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/impl/PathsStream.java @@ -16,6 +16,9 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; +import java.nio.ByteBuffer; +import java.nio.channels.Channels; +import java.nio.channels.ReadableByteChannel; import java.nio.charset.StandardCharsets; import java.util.ArrayDeque; import java.util.ArrayList; @@ -70,6 +73,7 @@ public final class PathsStream extends InputStream { private boolean hasRootPostLink; private boolean hasAddedDataStore; private Reader reader; + private ReadableByteChannel channel; public PathsStream(final EffectiveModelContext schemaContext, final OpenApiBodyWriter writer, final String deviceName, final String urlPrefix, final boolean isForSingleModule, @@ -98,7 +102,10 @@ public final class PathsStream extends InputStream { @Override public int read(final byte[] array, final int off, final int len) throws IOException { - return super.read(array, off, len); + if (channel == null) { + channel = Channels.newChannel(new ByteArrayInputStream(writeNextEntity(new PathsEntity(toPaths())))); + } + return channel.read(ByteBuffer.wrap(array, off, len)); } private byte[] writeNextEntity(final OpenApiEntity next) throws IOException { diff --git a/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/impl/SchemaStream.java b/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/impl/SchemaStream.java index 6036b7e48c..dc75c69950 100644 --- a/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/impl/SchemaStream.java +++ b/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/impl/SchemaStream.java @@ -13,6 +13,9 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; +import java.nio.ByteBuffer; +import java.nio.channels.Channels; +import java.nio.channels.ReadableByteChannel; import java.nio.charset.StandardCharsets; import java.util.Deque; import org.opendaylight.restconf.openapi.jaxrs.OpenApiBodyWriter; @@ -24,6 +27,7 @@ public final class SchemaStream extends InputStream { private final OpenApiBodyWriter writer; private Reader reader; + private ReadableByteChannel channel; public SchemaStream(final Deque schemas, final OpenApiBodyWriter writer) { this.stack = schemas; @@ -55,7 +59,23 @@ public final class SchemaStream extends InputStream { @Override public int read(final byte[] array, final int off, final int len) throws IOException { - return super.read(array, off, len); + if (channel == null) { + if (stack.isEmpty()) { + return -1; + } + channel = Channels.newChannel(new ByteArrayInputStream(writeNextEntity(stack.pop()))); + } + + var read = channel.read(ByteBuffer.wrap(array, off, len)); + while (read == -1) { + if (stack.isEmpty()) { + return -1; + } + channel = Channels.newChannel(new ByteArrayInputStream(writeNextEntity(stack.pop()))); + read = channel.read(ByteBuffer.wrap(array, off, len)); + } + + return read; } private byte[] writeNextEntity(final OpenApiEntity entity) throws IOException { diff --git a/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/impl/SchemasStream.java b/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/impl/SchemasStream.java index c002e64010..fa4e8280d4 100644 --- a/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/impl/SchemasStream.java +++ b/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/impl/SchemasStream.java @@ -15,6 +15,9 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; +import java.nio.ByteBuffer; +import java.nio.channels.Channels; +import java.nio.channels.ReadableByteChannel; import java.nio.charset.StandardCharsets; import java.util.ArrayDeque; import java.util.ArrayList; @@ -46,6 +49,7 @@ public final class SchemasStream extends InputStream { private final boolean isForSingleModule; private Reader reader; + private ReadableByteChannel channel; private boolean schemesWritten; public SchemasStream(final EffectiveModelContext context, final OpenApiBodyWriter writer, @@ -95,7 +99,33 @@ public final class SchemasStream extends InputStream { @Override public int read(final byte[] array, final int off, final int len) throws IOException { - return super.read(array, off, len); + if (channel == null) { + generator.writeObjectFieldStart("schemas"); + generator.flush(); + channel = Channels.newChannel(new ByteArrayInputStream(stream.toByteArray())); + stream.reset(); + } + + var read = channel.read(ByteBuffer.wrap(array, off, len)); + while (read == -1) { + if (iterator.hasNext()) { + channel = Channels.newChannel(new SchemaStream(toComponents(iterator.next(), context, + isForSingleModule), writer)); + read = channel.read(ByteBuffer.wrap(array, off, len)); + continue; + } + if (!schemesWritten) { + generator.writeEndObject(); + schemesWritten = true; + continue; + } + generator.flush(); + channel = Channels.newChannel(new ByteArrayInputStream(stream.toByteArray())); + stream.reset(); + return channel.read(ByteBuffer.wrap(array, off, len)); + } + + return read; } private static Deque toComponents(final Module module, final EffectiveModelContext context, diff --git a/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/impl/SecuritySchemesStream.java b/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/impl/SecuritySchemesStream.java index 73e40c9079..5c7e53b5b2 100644 --- a/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/impl/SecuritySchemesStream.java +++ b/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/impl/SecuritySchemesStream.java @@ -13,6 +13,9 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; +import java.nio.ByteBuffer; +import java.nio.channels.Channels; +import java.nio.channels.ReadableByteChannel; import java.nio.charset.StandardCharsets; import java.util.Map; import org.opendaylight.restconf.openapi.jaxrs.OpenApiBodyWriter; @@ -25,6 +28,7 @@ public final class SecuritySchemesStream extends InputStream { private final SecuritySchemesEntity securitySchemesEntity; private Reader reader; + private ReadableByteChannel channel; public SecuritySchemesStream(final OpenApiBodyWriter writer, final Map securitySchemes) { @@ -44,7 +48,11 @@ public final class SecuritySchemesStream extends InputStream { @Override public int read(final byte[] array, final int off, final int len) throws IOException { - return super.read(array, off, len); + if (channel == null) { + final var stream = new ByteArrayInputStream(writeNextEntity(securitySchemesEntity)); + channel = Channels.newChannel(stream); + } + return channel.read(ByteBuffer.wrap(array, off, len)); } private byte[] writeNextEntity(final OpenApiEntity next) throws IOException { diff --git a/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/impl/SecurityStream.java b/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/impl/SecurityStream.java index 0cea95ff84..f3d16505fa 100644 --- a/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/impl/SecurityStream.java +++ b/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/impl/SecurityStream.java @@ -13,6 +13,9 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; +import java.nio.ByteBuffer; +import java.nio.channels.Channels; +import java.nio.channels.ReadableByteChannel; import java.nio.charset.StandardCharsets; import org.opendaylight.restconf.openapi.jaxrs.OpenApiBodyWriter; import org.opendaylight.restconf.openapi.model.OpenApiEntity; @@ -23,6 +26,7 @@ public final class SecurityStream extends InputStream { private final SecurityEntity entity; private Reader reader; + private ReadableByteChannel channel; public SecurityStream(final OpenApiBodyWriter writer, final SecurityEntity entity) { this.writer = writer; @@ -40,7 +44,10 @@ public final class SecurityStream extends InputStream { @Override public int read(final byte[] array, final int off, final int len) throws IOException { - return super.read(array, off, len); + if (channel == null) { + channel = Channels.newChannel(new ByteArrayInputStream(writeNextEntity(entity))); + } + return channel.read(ByteBuffer.wrap(array, off, len)); } private byte[] writeNextEntity(final OpenApiEntity next) throws IOException { diff --git a/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/impl/ServersStream.java b/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/impl/ServersStream.java index db8194a862..bff54b2e54 100644 --- a/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/impl/ServersStream.java +++ b/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/impl/ServersStream.java @@ -13,6 +13,9 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; +import java.nio.ByteBuffer; +import java.nio.channels.Channels; +import java.nio.channels.ReadableByteChannel; import java.nio.charset.StandardCharsets; import org.opendaylight.restconf.openapi.jaxrs.OpenApiBodyWriter; import org.opendaylight.restconf.openapi.model.OpenApiEntity; @@ -23,6 +26,7 @@ public final class ServersStream extends InputStream { private final OpenApiBodyWriter writer; private Reader reader; + private ReadableByteChannel channel; public ServersStream(final ServersEntity entity, final OpenApiBodyWriter writer) { this.entity = entity; @@ -40,7 +44,10 @@ public final class ServersStream extends InputStream { @Override public int read(final byte[] array, final int off, final int len) throws IOException { - return super.read(array, off, len); + if (channel == null) { + channel = Channels.newChannel(new ByteArrayInputStream(writeNextEntity(entity))); + } + return channel.read(ByteBuffer.wrap(array, off, len)); } private byte[] writeNextEntity(final OpenApiEntity next) throws IOException { -- 2.36.6