@Override public void write(int b) throws IOException { _written += 1; boolean complete = _channel.getResponse().isAllContentWritten(_written); // Async or Blocking ? while (true) { switch (_state.get()) { case OPEN: if (_aggregate == null) _aggregate = _channel .getByteBufferPool() .acquire(getBufferSize(), _interceptor.isOptimizedForDirectBuffers()); BufferUtil.append(_aggregate, (byte) b); // Check if all written or full if (complete || BufferUtil.isFull(_aggregate)) { write(_aggregate, complete); if (complete) closed(); } break; case ASYNC: throw new IllegalStateException("isReady() not called"); case READY: if (!_state.compareAndSet(OutputState.READY, OutputState.PENDING)) continue; if (_aggregate == null) _aggregate = _channel .getByteBufferPool() .acquire(getBufferSize(), _interceptor.isOptimizedForDirectBuffers()); BufferUtil.append(_aggregate, (byte) b); // Check if all written or full if (!complete && !BufferUtil.isFull(_aggregate)) { if (!_state.compareAndSet(OutputState.PENDING, OutputState.ASYNC)) throw new IllegalStateException(); return; } // Do the asynchronous writing from the callback new AsyncFlush().iterate(); return; case PENDING: case UNREADY: throw new WritePendingException(); case ERROR: throw new EofException(_onError); case CLOSED: throw new EofException("Closed"); default: throw new IllegalStateException(); } break; } }
@Override public void write(byte[] b, int off, int len) throws IOException { _written += len; boolean complete = _channel.getResponse().isAllContentWritten(_written); // Async or Blocking ? while (true) { switch (_state.get()) { case OPEN: // process blocking below break; case ASYNC: throw new IllegalStateException("isReady() not called"); case READY: if (!_state.compareAndSet(OutputState.READY, OutputState.PENDING)) continue; // Should we aggregate? if (!complete && len <= _commitSize) { if (_aggregate == null) _aggregate = _channel .getByteBufferPool() .acquire(getBufferSize(), _interceptor.isOptimizedForDirectBuffers()); // YES - fill the aggregate with content from the buffer int filled = BufferUtil.fill(_aggregate, b, off, len); // return if we are not complete, not full and filled all the content if (filled == len && !BufferUtil.isFull(_aggregate)) { if (!_state.compareAndSet(OutputState.PENDING, OutputState.ASYNC)) throw new IllegalStateException(); return; } // adjust offset/length off += filled; len -= filled; } // Do the asynchronous writing from the callback new AsyncWrite(b, off, len, complete).iterate(); return; case PENDING: case UNREADY: throw new WritePendingException(); case ERROR: throw new EofException(_onError); case CLOSED: throw new EofException("Closed"); default: throw new IllegalStateException(); } break; } // handle blocking write // Should we aggregate? int capacity = getBufferSize(); if (!complete && len <= _commitSize) { if (_aggregate == null) _aggregate = _channel .getByteBufferPool() .acquire(capacity, _interceptor.isOptimizedForDirectBuffers()); // YES - fill the aggregate with content from the buffer int filled = BufferUtil.fill(_aggregate, b, off, len); // return if we are not complete, not full and filled all the content if (filled == len && !BufferUtil.isFull(_aggregate)) return; // adjust offset/length off += filled; len -= filled; } // flush any content from the aggregate if (BufferUtil.hasContent(_aggregate)) { write(_aggregate, complete && len == 0); // should we fill aggregate again from the buffer? if (len > 0 && !complete && len <= _commitSize && len <= BufferUtil.space(_aggregate)) { BufferUtil.append(_aggregate, b, off, len); return; } } // write any remaining content in the buffer directly if (len > 0) { ByteBuffer wrap = ByteBuffer.wrap(b, off, len); ByteBuffer view = wrap.duplicate(); // write a buffer capacity at a time to avoid JVM pooling large direct buffers // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6210541 while (len > getBufferSize()) { int p = view.position(); int l = p + getBufferSize(); view.limit(p + getBufferSize()); write(view, false); len -= getBufferSize(); view.limit(l + Math.min(len, getBufferSize())); view.position(l); } write(view, complete); } else if (complete) { write(BufferUtil.EMPTY_BUFFER, true); } if (complete) closed(); }