5b97b7b52faa3519cac5c45d048bba1bb2295582
[netconf.git] / restconf / restconf-openapi / src / main / java / org / opendaylight / restconf / openapi / impl / ComponentsStream.java
1 /*
2  * Copyright (c) 2024 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.impl;
9
10 import com.fasterxml.jackson.core.JsonGenerator;
11 import java.io.ByteArrayInputStream;
12 import java.io.ByteArrayOutputStream;
13 import java.io.IOException;
14 import java.io.InputStream;
15 import java.io.InputStreamReader;
16 import java.io.Reader;
17 import java.nio.ByteBuffer;
18 import java.nio.channels.Channels;
19 import java.nio.channels.ReadableByteChannel;
20 import java.nio.charset.StandardCharsets;
21 import java.util.Iterator;
22 import java.util.Map;
23 import org.opendaylight.restconf.openapi.jaxrs.OpenApiBodyWriter;
24 import org.opendaylight.restconf.openapi.model.security.Http;
25 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
26 import org.opendaylight.yangtools.yang.model.api.Module;
27
28 public final class ComponentsStream extends InputStream {
29     private static final String BASIC_AUTH_NAME = "basicAuth";
30     private static final Http OPEN_API_BASIC_AUTH = new Http("basic", null, null);
31
32     private final Iterator<? extends Module> iterator;
33     private final OpenApiBodyWriter writer;
34     private final EffectiveModelContext context;
35     private final JsonGenerator generator;
36     private final ByteArrayOutputStream stream;
37     private final boolean isForSingleModule;
38
39     private boolean schemasWritten;
40     private boolean securityWritten;
41     private Reader reader;
42     private ReadableByteChannel channel;
43
44     public ComponentsStream(final EffectiveModelContext context, final OpenApiBodyWriter writer,
45         final JsonGenerator generator, final ByteArrayOutputStream stream,
46         final Iterator<? extends Module> iterator, final boolean isForSingleModule) {
47         this.iterator = iterator;
48         this.context = context;
49         this.writer = writer;
50         this.generator = generator;
51         this.stream = stream;
52         this.isForSingleModule = isForSingleModule;
53     }
54
55     @Override
56     public int read() throws IOException {
57         if (reader == null) {
58             generator.writeObjectFieldStart("components");
59             generator.flush();
60             reader = new InputStreamReader(new ByteArrayInputStream(stream.toByteArray()), StandardCharsets.UTF_8);
61             stream.reset();
62         }
63
64         var read = reader.read();
65         while (read == -1) {
66             if (!schemasWritten) {
67                 reader = new InputStreamReader(new SchemasStream(context, writer, generator, stream, iterator,
68                     isForSingleModule), StandardCharsets.UTF_8);
69                 read = reader.read();
70                 schemasWritten = true;
71                 continue;
72             }
73             if (!securityWritten) {
74                 reader = new InputStreamReader(new SecuritySchemesStream(writer, Map.of(BASIC_AUTH_NAME,
75                     OPEN_API_BASIC_AUTH)), StandardCharsets.UTF_8);
76                 read = reader.read();
77                 securityWritten = true;
78                 generator.writeEndObject();
79                 continue;
80             }
81             generator.flush();
82             reader = new InputStreamReader(new ByteArrayInputStream(stream.toByteArray()), StandardCharsets.UTF_8);
83             stream.reset();
84             return reader.read();
85         }
86         return read;
87     }
88
89     @Override
90     public int read(final byte[] array, final int off, final int len) throws IOException {
91         if (channel == null) {
92             generator.writeObjectFieldStart("components");
93             generator.flush();
94             channel = Channels.newChannel(new ByteArrayInputStream(stream.toByteArray()));
95             stream.reset();
96         }
97
98         var read = channel.read(ByteBuffer.wrap(array, off, len));
99         while (read == -1) {
100             if (!schemasWritten) {
101                 channel = Channels.newChannel(new SchemasStream(context, writer, generator, stream, iterator,
102                     isForSingleModule));
103                 read = channel.read(ByteBuffer.wrap(array));
104                 schemasWritten = true;
105                 continue;
106             }
107             if (!securityWritten) {
108                 channel = Channels.newChannel(new SecuritySchemesStream(writer, Map.of(BASIC_AUTH_NAME,
109                     OPEN_API_BASIC_AUTH)));
110                 read = channel.read(ByteBuffer.wrap(array, off, len));
111                 securityWritten = true;
112                 generator.writeEndObject();
113                 continue;
114             }
115             generator.flush();
116             channel = Channels.newChannel(new ByteArrayInputStream(stream.toByteArray()));
117             stream.reset();
118             return channel.read(ByteBuffer.wrap(array, off, len));
119         }
120         return read;
121     }
122 }