001/*
002 * Copyright 2024 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.Nullable;
021import javax.annotation.concurrent.NotThreadSafe;
022import java.io.PrintWriter;
023import java.io.Writer;
024import java.util.Locale;
025import java.util.function.Consumer;
026
027import static java.util.Objects.requireNonNull;
028
029/**
030 * @author <a href="https://www.revetkn.com">Mark Allen</a>
031 */
032@NotThreadSafe
033public class SokletServletPrintWriter extends PrintWriter {
034        @Nonnull
035        private final Consumer<SokletServletPrintWriter> writeOccurredCallback;
036        @Nonnull
037        private final Consumer<SokletServletPrintWriter> writeFinalizedCallback;
038        @Nonnull
039        private Boolean writeFinalized = false;
040
041        public SokletServletPrintWriter(@Nonnull Writer writer) {
042                this(requireNonNull(writer), null, null);
043        }
044
045        public SokletServletPrintWriter(@Nonnull Writer writer,
046                                                                                                                                        @Nullable Consumer<SokletServletPrintWriter> writeOccurredCallback,
047                                                                                                                                        @Nullable Consumer<SokletServletPrintWriter> writeFinalizedCallback) {
048                super(requireNonNull(writer), true);
049
050                if (writeOccurredCallback == null)
051                        writeOccurredCallback = (ignored) -> {};
052
053                if (writeFinalizedCallback == null)
054                        writeFinalizedCallback = (ignored) -> {};
055
056                this.writeOccurredCallback = writeOccurredCallback;
057                this.writeFinalizedCallback = writeFinalizedCallback;
058        }
059
060        @Nonnull
061        protected Boolean getWriteFinalized() {
062                return this.writeFinalized;
063        }
064
065        protected void setWriteFinalized(@Nonnull Boolean writeFinalized) {
066                requireNonNull(writeFinalized);
067                this.writeFinalized = writeFinalized;
068        }
069
070        @Nonnull
071        protected Consumer<SokletServletPrintWriter> getWriteOccurredCallback() {
072                return this.writeOccurredCallback;
073        }
074
075        @Nonnull
076        protected Consumer<SokletServletPrintWriter> getWriteFinalizedCallback() {
077                return this.writeFinalizedCallback;
078        }
079
080// Implementation of PrintWriter methods below:
081
082        @Override
083        public void write(@Nonnull char[] buf,
084                                                                                int off,
085                                                                                int len) {
086                requireNonNull(buf);
087
088                super.write(buf, off, len);
089                super.flush();
090                getWriteOccurredCallback().accept(this);
091        }
092
093        @Override
094        public void write(@Nonnull String s,
095                                                                                int off,
096                                                                                int len) {
097                requireNonNull(s);
098
099                super.write(s, off, len);
100                super.flush();
101                getWriteOccurredCallback().accept(this);
102        }
103
104        @Override
105        public void write(int c) {
106                super.write(c);
107                super.flush();
108                getWriteOccurredCallback().accept(this);
109        }
110
111        @Override
112        public void write(@Nonnull char[] buf) {
113                requireNonNull(buf);
114
115                super.write(buf);
116                super.flush();
117                getWriteOccurredCallback().accept(this);
118        }
119
120        @Override
121        public void write(@Nonnull String s) {
122                requireNonNull(s);
123
124                super.write(s);
125                super.flush();
126                getWriteOccurredCallback().accept(this);
127        }
128
129        @Override
130        public void print(boolean b) {
131                super.print(b);
132                super.flush();
133                getWriteOccurredCallback().accept(this);
134        }
135
136        @Override
137        public void print(char c) {
138                super.print(c);
139                super.flush();
140                getWriteOccurredCallback().accept(this);
141        }
142
143        @Override
144        public void print(int i) {
145                super.print(i);
146                super.flush();
147                getWriteOccurredCallback().accept(this);
148        }
149
150        @Override
151        public void print(long l) {
152                super.print(l);
153                super.flush();
154                getWriteOccurredCallback().accept(this);
155        }
156
157        @Override
158        public void print(float f) {
159                super.print(f);
160                super.flush();
161                getWriteOccurredCallback().accept(this);
162        }
163
164        @Override
165        public void print(double d) {
166                super.print(d);
167                super.flush();
168                getWriteOccurredCallback().accept(this);
169        }
170
171        @Override
172        public void print(@Nonnull char[] s) {
173                requireNonNull(s);
174
175                super.print(s);
176                super.flush();
177                getWriteOccurredCallback().accept(this);
178        }
179
180        @Override
181        public void print(@Nullable String s) {
182                super.print(s);
183                super.flush();
184                getWriteOccurredCallback().accept(this);
185        }
186
187        @Override
188        public void print(@Nullable Object obj) {
189                super.print(obj);
190                super.flush();
191                getWriteOccurredCallback().accept(this);
192        }
193
194        @Override
195        public void println() {
196                super.println();
197                super.flush();
198                getWriteOccurredCallback().accept(this);
199        }
200
201        @Override
202        public void println(boolean x) {
203                super.println(x);
204                super.flush();
205                getWriteOccurredCallback().accept(this);
206        }
207
208        @Override
209        public void println(char x) {
210                super.println(x);
211                super.flush();
212                getWriteOccurredCallback().accept(this);
213        }
214
215        @Override
216        public void println(int x) {
217                super.println(x);
218                super.flush();
219                getWriteOccurredCallback().accept(this);
220        }
221
222        @Override
223        public void println(long x) {
224                super.println(x);
225                super.flush();
226                getWriteOccurredCallback().accept(this);
227        }
228
229        @Override
230        public void println(float x) {
231                super.println(x);
232                super.flush();
233                getWriteOccurredCallback().accept(this);
234        }
235
236        @Override
237        public void println(double x) {
238                super.println(x);
239                super.flush();
240                getWriteOccurredCallback().accept(this);
241        }
242
243        @Override
244        public void println(char[] x) {
245                requireNonNull(x);
246
247                super.println(x);
248                super.flush();
249                getWriteOccurredCallback().accept(this);
250        }
251
252        @Override
253        public void println(@Nullable String x) {
254                super.println(x);
255                super.flush();
256                getWriteOccurredCallback().accept(this);
257        }
258
259        @Override
260        public void println(@Nullable Object x) {
261                super.println(x);
262                super.flush();
263                getWriteOccurredCallback().accept(this);
264        }
265
266        @Override
267        @Nonnull
268        public PrintWriter printf(@Nonnull String format,
269                                                                                                                @Nullable Object... args) {
270                requireNonNull(format);
271
272                PrintWriter printWriter = super.printf(format, args);
273                super.flush();
274                getWriteOccurredCallback().accept(this);
275                return printWriter;
276        }
277
278        @Override
279        @Nonnull
280        public PrintWriter printf(@Nullable Locale l,
281                                                                                                                @Nonnull String format,
282                                                                                                                @Nullable Object... args) {
283                requireNonNull(format);
284
285                PrintWriter printWriter = super.printf(l, format, args);
286                super.flush();
287                getWriteOccurredCallback().accept(this);
288                return printWriter;
289        }
290
291        @Override
292        @Nonnull
293        public PrintWriter format(@Nonnull String format,
294                                                                                                                @Nullable Object... args) {
295                requireNonNull(format);
296
297                PrintWriter printWriter = super.format(format, args);
298                super.flush();
299                getWriteOccurredCallback().accept(this);
300                return printWriter;
301        }
302
303        @Override
304        @Nonnull
305        public PrintWriter format(@Nullable Locale l,
306                                                                                                                @Nonnull String format,
307                                                                                                                @Nullable Object... args) {
308                requireNonNull(format);
309
310                PrintWriter printWriter = super.format(l, format, args);
311                super.flush();
312                getWriteOccurredCallback().accept(this);
313                return printWriter;
314        }
315
316        @Override
317        @Nonnull
318        public PrintWriter append(@Nullable CharSequence csq) {
319                PrintWriter printWriter = super.append(csq);
320                super.flush();
321                getWriteOccurredCallback().accept(this);
322                return printWriter;
323        }
324
325        @Override
326        @Nonnull
327        public PrintWriter append(@Nullable CharSequence csq,
328                                                                                                                int start,
329                                                                                                                int end) {
330                PrintWriter printWriter = super.append(csq, start, end);
331                super.flush();
332                getWriteOccurredCallback().accept(this);
333                return printWriter;
334        }
335
336        @Override
337        @Nonnull
338        public PrintWriter append(char c) {
339                PrintWriter printWriter = super.append(c);
340                super.flush();
341                getWriteOccurredCallback().accept(this);
342                return printWriter;
343        }
344
345        @Override
346        public void flush() {
347                super.flush();
348
349                if (!getWriteFinalized()) {
350                        setWriteFinalized(true);
351                        getWriteFinalizedCallback().accept(this);
352                }
353        }
354
355        @Override
356        public void close() {
357                super.flush();
358                super.close();
359
360                if (!getWriteFinalized()) {
361                        setWriteFinalized(true);
362                        getWriteFinalizedCallback().accept(this);
363                }
364        }
365}