/** * ============LICENSE_START==================================================== * org.onap.aaf * =========================================================================== * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. * =========================================================================== * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ============LICENSE_END==================================================== * */ package org.onap.aaf.cadi; import java.io.IOException; import java.io.InputStream; import javax.servlet.ServletInputStream; /** * BufferedServletInputStream * * There are cases in brain-dead middleware (SOAP) where they store routing information in the content. * * In HTTP, this requires reading the content from the InputStream which, of course, cannot be re-read. * * BufferedInputStream exists to implement the "Mark" protocols for Streaming, which will enable being * re-read. Unfortunately, J2EE chose to require a "ServletInputStream" as an abstract class, rather than * an interface, which requires we create a delegating pattern, rather than the preferred inheriting pattern. * * Unfortunately, the standard "BufferedInputStream" cannot be used, because it simply creates a byte array * in the "mark(int)" method of that size. This is not appropriate for this application, because the Header * can be potentially huge, and if a buffer was allocated to accommodate all possibilities, the cost of memory * allocation would be too large for high performance transactions. * * * @author Jonathan * */ public class BufferedServletInputStream extends ServletInputStream { private static final int NONE = 0; private static final int STORE = 1; private static final int READ = 2; private InputStream is; private int state = NONE; private Capacitor capacitor; public BufferedServletInputStream(InputStream is) { this.is = is; capacitor = null; } public int read() throws IOException { int value=-1; if (capacitor==null) { value=is.read(); } else { switch(state) { case STORE: value = is.read(); if (value>=0) { capacitor.put((byte)value); } break; case READ: value = capacitor.read(); if (value<0) { capacitor.done(); capacitor=null; // all done with buffer value = is.read(); } } } return value; } @Override public int read(byte[] b) throws IOException { return read(b,0,b.length); } @Override public int read(byte[] b, int off, int len) throws IOException { int count = -1; if (capacitor==null) { count = is.read(b,off,len); } else { switch(state) { case STORE: count = is.read(b, off, len); if (count>0) { capacitor.put(b, off, count); } break; case READ: count = capacitor.read(b, off, len); if (count<=0) { capacitor.done(); capacitor=null; // all done with buffer } if (count0) { // watch for -1 count+=temp; } else if (count<=0) { count = temp; // must account for Stream coming back -1 } } break; } } return count; } public long skip(long n) throws IOException { long skipped = capacitor.skip(n); if (skipped