1 /*******************************************************************************
\r
2 * ============LICENSE_START====================================================
\r
4 * * ===========================================================================
\r
5 * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
\r
6 * * ===========================================================================
\r
7 * * Licensed under the Apache License, Version 2.0 (the "License");
\r
8 * * you may not use this file except in compliance with the License.
\r
9 * * You may obtain a copy of the License at
\r
11 * * http://www.apache.org/licenses/LICENSE-2.0
\r
13 * * Unless required by applicable law or agreed to in writing, software
\r
14 * * distributed under the License is distributed on an "AS IS" BASIS,
\r
15 * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
\r
16 * * See the License for the specific language governing permissions and
\r
17 * * limitations under the License.
\r
18 * * ============LICENSE_END====================================================
\r
20 * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
\r
22 ******************************************************************************/
\r
23 package org.onap.aaf.cadi;
\r
25 import java.io.IOException;
\r
26 import java.io.InputStream;
\r
28 import javax.servlet.ServletInputStream;
\r
31 * BufferedServletInputStream
\r
33 * There are cases in brain-dead middleware (SOAP) where they store routing information in the content.
\r
35 * In HTTP, this requires reading the content from the InputStream which, of course, cannot be re-read.
\r
37 * BufferedInputStream exists to implement the "Mark" protocols for Streaming, which will enable being
\r
38 * re-read. Unfortunately, J2EE chose to require a "ServletInputStream" as an abstract class, rather than
\r
39 * an interface, which requires we create a delegating pattern, rather than the preferred inheriting pattern.
\r
41 * Unfortunately, the standard "BufferedInputStream" cannot be used, because it simply creates a byte array
\r
42 * in the "mark(int)" method of that size. This is not appropriate for this application, because the Header
\r
43 * can be potentially huge, and if a buffer was allocated to accommodate all possibilities, the cost of memory
\r
44 * allocation would be too large for high performance transactions.
\r
49 public class BufferedServletInputStream extends ServletInputStream {
\r
50 private static final int NONE = 0;
\r
51 private static final int STORE = 1;
\r
52 private static final int READ = 2;
\r
54 private InputStream is;
\r
55 private int state = NONE;
\r
56 private Capacitor capacitor;
\r
58 public BufferedServletInputStream(InputStream is) {
\r
65 public int read() throws IOException {
\r
67 if(capacitor==null) {
\r
74 capacitor.put((byte)value);
\r
78 value = capacitor.read();
\r
81 capacitor=null; // all done with buffer
\r
90 public int read(byte[] b) throws IOException {
\r
91 return read(b,0,b.length);
\r
96 public int read(byte[] b, int off, int len) throws IOException {
\r
98 if(capacitor==null) {
\r
99 count = is.read(b,off,len);
\r
103 count = is.read(b, off, len);
\r
105 capacitor.put(b, off, count);
\r
109 count = capacitor.read(b, off, len);
\r
110 // System.out.println("Capacitor read " + count);
\r
113 capacitor=null; // all done with buffer
\r
116 int temp = is.read(b, count, len-count);
\r
117 // System.out.println("Capacitor done, stream read " + temp);
\r
118 if(temp>0) { // watch for -1
\r
121 if(count<=0)count = temp; // must account for Stream coming back -1
\r
127 // System.out.println("read reports " + count);
\r
132 public long skip(long n) throws IOException {
\r
133 long skipped = capacitor.skip(n);
\r
135 skipped += is.skip(n-skipped);
\r
142 public int available() throws IOException {
\r
143 int count = is.available();
\r
144 if(capacitor!=null)count+=capacitor.available();
\r
149 * Return just amount buffered (for debugging purposes, mostly)
\r
152 public int buffered() {
\r
153 return capacitor.available();
\r
158 public void close() throws IOException {
\r
159 if(capacitor!=null) {
\r
168 * Note: Readlimit is ignored in this implementation, because the need was for unknown buffer size which wouldn't
\r
169 * require allocating and dumping huge chunks of memory every use, or risk overflow.
\r
172 public synchronized void mark(int readlimit) {
\r
175 capacitor = new Capacitor();
\r
180 // ignore case STORE:
\r
189 * Calling this twice is not supported in typical Stream situations, but it is allowed in this service. The caveat is that it can only reset
\r
190 * the data read in since Mark has been called. The data integrity is only valid if you have not continued to read past what is stored.
\r
194 public synchronized void reset() throws IOException {
\r
197 capacitor.setForRead();
\r
203 // throw new IOException("InputStream is already in READ state");
\r
205 throw new IOException("InputStream has not been marked");
\r
211 public boolean markSupported() {
\r