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.impl;
10 import com.fasterxml.jackson.core.JsonFactoryBuilder;
11 import com.fasterxml.jackson.core.JsonGenerator;
12 import java.io.BufferedReader;
13 import java.io.ByteArrayInputStream;
14 import java.io.ByteArrayOutputStream;
15 import java.io.IOException;
16 import java.io.InputStream;
17 import java.io.InputStreamReader;
18 import java.io.Reader;
19 import java.nio.ByteBuffer;
20 import java.nio.channels.Channels;
21 import java.nio.channels.ReadableByteChannel;
22 import java.nio.charset.StandardCharsets;
23 import java.util.ArrayDeque;
24 import java.util.Collection;
25 import java.util.Deque;
26 import java.util.List;
28 import org.opendaylight.restconf.openapi.jaxrs.OpenApiBodyWriter;
29 import org.opendaylight.restconf.openapi.model.InfoEntity;
30 import org.opendaylight.restconf.openapi.model.OpenApiVersionEntity;
31 import org.opendaylight.restconf.openapi.model.SecurityEntity;
32 import org.opendaylight.restconf.openapi.model.ServerEntity;
33 import org.opendaylight.restconf.openapi.model.ServersEntity;
34 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
35 import org.opendaylight.yangtools.yang.model.api.Module;
37 public final class OpenApiInputStream extends InputStream {
38 private final ByteArrayOutputStream stream = new ByteArrayOutputStream();
39 private final JsonGenerator generator = new JsonFactoryBuilder().build().createGenerator(stream);
40 private final Deque<InputStream> stack = new ArrayDeque<>();
42 private Reader reader;
43 private ReadableByteChannel channel;
47 public OpenApiInputStream(final EffectiveModelContext context, final String title, final String url,
48 final List<Map<String, List<String>>> security, final String deviceName, final String urlPrefix,
49 final boolean isForSingleModule, final boolean includeDataStore, final Collection<? extends Module> modules,
50 final String basePath) throws IOException {
51 final OpenApiBodyWriter writer = new OpenApiBodyWriter(generator, stream);
52 stack.add(new OpenApiVersionStream(new OpenApiVersionEntity(), writer));
53 stack.add(new InfoStream(new InfoEntity(title), writer));
54 stack.add(new ServersStream(new ServersEntity(List.of(new ServerEntity(url))), writer));
55 stack.add(new PathsStream(context, writer, deviceName, urlPrefix, isForSingleModule, includeDataStore,
56 modules.iterator(), basePath, stream, generator));
57 stack.add(new ComponentsStream(context, writer, generator, stream, modules.iterator(), isForSingleModule));
58 stack.add(new SecurityStream(writer, new SecurityEntity(security)));
62 public int read() throws IOException {
67 generator.writeStartObject();
69 reader = new BufferedReader(
70 new InputStreamReader(new ByteArrayInputStream(stream.toByteArray()), StandardCharsets.UTF_8));
74 var read = reader.read();
76 if (stack.isEmpty()) {
77 generator.writeEndObject();
79 reader = new BufferedReader(
80 new InputStreamReader(new ByteArrayInputStream(stream.toByteArray()), StandardCharsets.UTF_8));
85 reader = new BufferedReader(new InputStreamReader(stack.pop(), StandardCharsets.UTF_8));
93 public int read(final byte[] array, final int off, final int len) throws IOException {
97 if (channel == null) {
98 generator.writeStartObject();
100 channel = Channels.newChannel(new ByteArrayInputStream(stream.toByteArray()));
104 var read = channel.read(ByteBuffer.wrap(array, off, len));
106 if (stack.isEmpty()) {
107 generator.writeEndObject();
109 channel = Channels.newChannel(new ByteArrayInputStream(stream.toByteArray()));
112 return channel.read(ByteBuffer.wrap(array, off, len));
114 channel = Channels.newChannel(stack.pop());
115 read = channel.read(ByteBuffer.wrap(array, off, len));