1 /* 2 * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.net.http; 27 28 import java.nio.ByteBuffer; 29 import java.util.ArrayList; 30 31 /** 32 * Manages a ByteBuffer[] for writing frames into for output. The last 33 * ByteBuffer in the list is always unflipped (able to receive more bytes for 34 * sending) until getBufferArray() is called, which calls finish(). 35 * 36 * This allows multiple frames to be written to the same BBG. 37 * 38 * Buffers added with addByteBuffer() must be already flipped. 39 */ 40 class ByteBufferGenerator { 41 42 ByteBuffer currentBuffer; 43 // source is assumed to always return the same sized buffer 44 final BufferHandler pool; 45 final ArrayList<ByteBuffer> buflist; 46 final int bufsize; 47 boolean finished; 48 49 ByteBufferGenerator(BufferHandler pool) { 50 this.buflist = new ArrayList<>(); 51 this.pool = pool; 52 this.currentBuffer = pool.getBuffer(); 53 this.bufsize = currentBuffer.capacity(); 54 } 55 56 private static final ByteBuffer[] EMPTY = new ByteBuffer[0]; 57 58 public ByteBuffer[] getBufferArray() { 59 finish(); 60 return buflist.toArray(EMPTY); 61 } 62 63 public ArrayList<ByteBuffer> getBufferList() { 64 finish(); 65 return buflist; 66 } 67 68 private synchronized void finish() { 69 if (finished) { 70 return; 71 } 72 finished = true; 73 currentBuffer.flip(); 74 if (currentBuffer.hasRemaining()) { 75 buflist.add(currentBuffer); 76 } else { 77 pool.returnBuffer(currentBuffer); 78 } 79 } 80 81 // only used for SettingsFrame: offset is number of bytes to 82 // ignore at start (we only want the payload of the settings frame) 83 public byte[] asByteArray(int offset) { 84 ByteBuffer[] bufs = getBufferArray(); 85 int size = 0; 86 for (ByteBuffer buf : bufs) { 87 size += buf.remaining(); 88 } 89 byte[] bytes = new byte[size-offset]; 90 int pos = 0; 91 for (ByteBuffer buf : bufs) { 92 int rem = buf.remaining(); 93 int ignore = Math.min(rem, offset); 94 buf.position(buf.position()+ignore); 95 rem -= ignore; 96 offset -= ignore; 97 buf.get(bytes, pos, rem); 98 pos += rem; 99 } 100 return bytes; 101 } 102 103 ByteBuffer getBuffer(long n) { 104 if (currentBuffer.remaining() < n) { 105 getNewBuffer(); 106 if (n > currentBuffer.capacity()) { 107 throw new IllegalArgumentException("requested buffer too large"); 108 } 109 } 110 return currentBuffer; 111 } 112 113 void getNewBuffer() { 114 currentBuffer.flip(); 115 if (currentBuffer.hasRemaining()) { 116 buflist.add(currentBuffer); 117 } else { 118 pool.returnBuffer(currentBuffer); 119 } 120 currentBuffer = pool.getBuffer(); 121 } 122 123 void addByteBuffer(ByteBuffer buf) { 124 getNewBuffer(); 125 buflist.add(buf); 126 } 127 128 void addPadding(int length) { 129 while (length > 0) { 130 int n = Math.min(length, bufsize); 131 ByteBuffer b = getBuffer(n); 132 // TODO: currently zeroed? 133 b.position(b.position() + n); 134 length -= n; 135 } 136 } 137 }