001/*
002 * Copyright 2024-2025 Revetware LLC.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package com.soklet.servlet.jakarta;
018
019import jakarta.servlet.ReadListener;
020import jakarta.servlet.ServletInputStream;
021
022import javax.annotation.Nonnull;
023import javax.annotation.concurrent.NotThreadSafe;
024import java.io.IOException;
025import java.io.InputStream;
026
027import static java.lang.String.format;
028import static java.util.Objects.requireNonNull;
029
030/**
031 * Soklet integration implementation of {@link ServletInputStream}.
032 *
033 * @author <a href="https://www.revetkn.com">Mark Allen</a>
034 */
035@NotThreadSafe
036public final class SokletServletInputStream extends ServletInputStream {
037        @Nonnull
038        private final InputStream inputStream;
039        @Nonnull
040        private Boolean finished;
041
042        @Nonnull
043        public static SokletServletInputStream withInputStream(@Nonnull InputStream inputStream) {
044                requireNonNull(inputStream);
045                return new SokletServletInputStream(inputStream);
046        }
047
048        private SokletServletInputStream(@Nonnull InputStream inputStream) {
049                super();
050                requireNonNull(inputStream);
051
052                this.inputStream = inputStream;
053                this.finished = false;
054        }
055
056        @Nonnull
057        protected InputStream getInputStream() {
058                return this.inputStream;
059        }
060
061        @Nonnull
062        protected Boolean getFinished() {
063                return this.finished;
064        }
065
066        protected void setFinished(@Nonnull Boolean finished) {
067                requireNonNull(finished);
068                this.finished = finished;
069        }
070
071        // Implementation of ServletInputStream methods below:
072
073        @Override
074        public boolean isFinished() {
075                return getFinished();
076        }
077
078        @Override
079        public boolean isReady() {
080                return true;
081        }
082
083        @Override
084        public int available() throws IOException {
085                return getInputStream().available();
086        }
087
088        @Override
089        public void close() throws IOException {
090                super.close();
091                getInputStream().close();
092        }
093
094        @Override
095        public void setReadListener(@Nonnull ReadListener readListener) {
096                requireNonNull(readListener);
097                throw new IllegalStateException(format("%s functionality is not supported", ReadListener.class.getSimpleName()));
098        }
099
100        @Override
101        public int read() throws IOException {
102                int data = getInputStream().read();
103
104                if (data == -1)
105                        setFinished(true);
106
107                return data;
108        }
109}