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 com.att.cadi;
\r
25 import java.nio.ByteBuffer;
\r
26 import java.util.ArrayList;
\r
31 * Storage mechanism for read data, specifically designed for InputStreams.
\r
33 * The Standard BufferedInputStream requires a limit to be set for buffered reading, which is
\r
34 * impractical for reading SOAP headers, which can be quite large.
\r
37 public class Capacitor {
\r
38 private static final int DEFAULT_CHUNK = 256;
\r
39 private ArrayList<ByteBuffer> bbs = new ArrayList<ByteBuffer>();
\r
40 private ByteBuffer curr = null;
\r
43 // Maintain a private RingBuffer for Memory, for efficiency
\r
44 private static ByteBuffer[] ring = new ByteBuffer[16];
\r
45 private static int start, end;
\r
48 public void put(byte b) {
\r
49 if(curr == null || curr.remaining()==0) { // ensure we have a "curr" buffer ready for data
\r
58 if(curr.remaining()>0) { // have a buffer, use it!
\r
60 } else if(idx<bbs.size()){ // Buffer not enough, get next one from array
\r
61 if(idx<bbs.size()) {
\r
62 curr=bbs.get(idx++);
\r
66 } // if no curr buffer, treat as end of stream
\r
71 * read into an array like Streams
\r
78 public int read(byte[] array, int offset, int length) {
\r
79 if(curr==null)return -1;
\r
82 while(length>0) { // loop through while there's data needed
\r
83 if((len=curr.remaining())>length) { // if enough data in curr buffer, use this code
\r
84 curr.get(array,offset,length);
\r
87 } else { // get data from curr, mark how much is needed to fulfil, and loop for next curr.
\r
88 curr.get(array,offset,len);
\r
92 if(idx<bbs.size()) {
\r
93 curr=bbs.get(idx++);
\r
95 length=0; // stop, and return the count of how many we were able to load
\r
103 * Put an array of data into Capacitor
\r
109 public void put(byte[] array, int offset, int length) {
\r
110 if(curr == null || curr.remaining()==0) {
\r
117 if((len=curr.remaining())>length) {
\r
118 curr.put(array,offset,length);
\r
121 // System.out.println(new String(array));
\r
122 curr.put(array,offset,len);
\r
132 * Move state from Storage mode into Read mode, changing all internal buffers to read mode, etc
\r
134 public void setForRead() {
\r
135 for(ByteBuffer bb : bbs) {
\r
138 if(bbs.isEmpty()) {
\r
148 * reuse all the buffers
\r
150 public void done() {
\r
151 for(ByteBuffer bb : bbs) {
\r
159 * Declare amount of data available to be read at once.
\r
163 public int available() {
\r
165 for(ByteBuffer bb : bbs) {
\r
166 count+=bb.remaining();
\r
172 * Returns how many are left that were not skipped
\r
176 public long skip(long n) {
\r
180 if(n<(skip=curr.remaining())) {
\r
181 curr.position(curr.position()+(int)n);
\r
185 curr.position(curr.limit());
\r
188 if(idx<bbs.size()) {
\r
189 curr=bbs.get(idx++);
\r
199 * Be able to re-read data that is stored that has already been re-read. This is not a standard Stream behavior, but can be useful
\r
200 * in a standalone mode.
\r
202 public void reset() {
\r
203 for(ByteBuffer bb : bbs) {
\r
206 if(bbs.isEmpty()) {
\r
216 * Ring Functions. Reuse allocated memory
\r
218 private ByteBuffer ringGet() {
\r
219 ByteBuffer bb = null;
\r
220 synchronized(ring) {
\r
223 if(bb!=null && ++start>15)start=0;
\r
226 bb=ByteBuffer.allocate(DEFAULT_CHUNK);
\r
228 bb.clear();// refresh reused buffer
\r
233 private void ringPut(ByteBuffer bb) {
\r
234 synchronized(ring) {
\r
235 ring[end]=bb; // if null or not, BB will just be Garbage collected
\r