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.javax;
018
019import javax.annotation.Nonnull;
020import javax.annotation.concurrent.NotThreadSafe;
021import javax.servlet.ReadListener;
022import javax.servlet.ServletInputStream;
023import java.io.IOException;
024import java.io.InputStream;
025
026import static java.lang.String.format;
027import static java.util.Objects.requireNonNull;
028
029/**
030 * Soklet integration implementation of {@link ServletInputStream}.
031 *
032 * @author <a href="https://www.revetkn.com">Mark Allen</a>
033 */
034@NotThreadSafe
035public final class SokletServletInputStream extends ServletInputStream {
036        @Nonnull
037        private final InputStream inputStream;
038        @Nonnull
039        private Boolean finished;
040
041        @Nonnull
042        public static SokletServletInputStream withInputStream(@Nonnull InputStream inputStream) {
043                requireNonNull(inputStream);
044                return new SokletServletInputStream(inputStream);
045        }
046
047        private SokletServletInputStream(@Nonnull InputStream inputStream) {
048                super();
049                requireNonNull(inputStream);
050
051                this.inputStream = inputStream;
052                this.finished = false;
053        }
054
055        @Nonnull
056        protected InputStream getInputStream() {
057                return this.inputStream;
058        }
059
060        @Nonnull
061        protected Boolean getFinished() {
062                return this.finished;
063        }
064
065        protected void setFinished(@Nonnull Boolean finished) {
066                requireNonNull(finished);
067                this.finished = finished;
068        }
069
070        // Implementation of ServletInputStream methods below:
071
072        @Override
073        public boolean isFinished() {
074                return getFinished();
075        }
076
077        @Override
078        public boolean isReady() {
079                return true;
080        }
081
082        @Override
083        public int available() throws IOException {
084                return getInputStream().available();
085        }
086
087        @Override
088        public void close() throws IOException {
089                super.close();
090                getInputStream().close();
091        }
092
093        @Override
094        public void setReadListener(@Nonnull ReadListener readListener) {
095                requireNonNull(readListener);
096                throw new IllegalStateException(format("%s functionality is not supported", ReadListener.class.getSimpleName()));
097        }
098
099        @Override
100        public int read() throws IOException {
101                int data = getInputStream().read();
102
103                if (data == -1)
104                        setFinished(true);
105
106                return data;
107        }
108}