< prev index next >
   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  */
  24 
  25 package java.net.http;
  26 
  27 import java.nio.ByteBuffer;
  28 import java.util.ArrayList;
  29 
  30 /**
  31  * Manages a ByteBuffer[] for writing frames into for output. The last
  32  * ByteBuffer in the list is always unflipped (able to receive more bytes for
  33  * sending) until getBufferArray() is called, which calls finish().
  34  *
  35  * This allows multiple frames to be written to the same BBG.
  36  *
  37  * Buffers added with addByteBuffer() must be already flipped.
  38  */
  39 class ByteBufferGenerator {
  40 
  41     ByteBuffer currentBuffer;
  42     // source is assumed to always return the same sized buffer
  43     final BufferHandler pool;
  44     final ArrayList<ByteBuffer> buflist;
  45     final int bufsize;
  46     boolean finished;
  47 
  48     ByteBufferGenerator(BufferHandler pool) {
  49         this.buflist = new ArrayList<>();
  50         this.pool = pool;
  51         this.currentBuffer = pool.getBuffer();
  52         this.bufsize = currentBuffer.capacity();
  53     }
  54 
  55     private static final ByteBuffer[] EMPTY = new ByteBuffer[0];
  56 
  57     public ByteBuffer[] getBufferArray() {
  58         finish();
  59         return buflist.toArray(EMPTY);
  60     }
  61 
  62     public ArrayList<ByteBuffer> getBufferList() {
  63         finish();
  64         return buflist;
  65     }
  66 
  67     private synchronized void finish() {
  68         if (finished) {
  69             return;
  70         }
  71         finished = true;
  72         currentBuffer.flip();
  73         if (currentBuffer.hasRemaining()) {
  74             buflist.add(currentBuffer);
  75         } else {
  76             pool.returnBuffer(currentBuffer);
  77         }
  78     }
  79 
  80     // only used for SettingsFrame: offset is number of bytes to
  81     // ignore at start (we only want the payload of the settings frame)
  82     public byte[] asByteArray(int offset) {
  83         ByteBuffer[] bufs = getBufferArray();
  84         int size = 0;
  85         for (ByteBuffer buf : bufs) {
  86             size += buf.remaining();
  87         }
  88         byte[] bytes = new byte[size-offset];
  89         int pos = 0;
  90         for (ByteBuffer buf : bufs) {
  91             int rem = buf.remaining();
  92             int ignore = Math.min(rem, offset);
  93             buf.position(buf.position()+ignore);
  94             rem -= ignore;
  95             offset -= ignore;
  96             buf.get(bytes, pos, rem);
  97             pos += rem;
  98         }
  99         return bytes;
 100     }
 101 
 102     ByteBuffer getBuffer(long n) {
 103         if (currentBuffer.remaining() < n) {
 104             getNewBuffer();
 105             if (n > currentBuffer.capacity()) {
 106                 throw new IllegalArgumentException("requested buffer too large");
 107             }
 108         }
 109         return currentBuffer;
 110     }
 111 
 112     void getNewBuffer() {
 113         currentBuffer.flip();
 114         if (currentBuffer.hasRemaining()) {
 115             buflist.add(currentBuffer);
 116         } else {
 117             pool.returnBuffer(currentBuffer);
 118         }
 119         currentBuffer = pool.getBuffer();
 120     }
 121 
 122     void addByteBuffer(ByteBuffer buf) {
 123         getNewBuffer();
 124         buflist.add(buf);
 125     }
 126 
 127     void addPadding(int length) {
 128         while (length > 0) {
 129             int n = Math.min(length, bufsize);
 130             ByteBuffer b = getBuffer(n);
 131             // TODO: currently zeroed?
 132             b.position(b.position() + n);
 133             length -= n;
 134         }
 135     }
 136 }
< prev index next >