//
//  ========================================================================
//  Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
//  ------------------------------------------------------------------------
//  All rights reserved. This program and the accompanying materials
//  are made available under the terms of the Eclipse Public License v1.0
//  and Apache License v2.0 which accompanies this distribution.
//
//      The Eclipse Public License is available at
//      http://www.eclipse.org/legal/epl-v10.html
//
//      The Apache License v2.0 is available at
//      http://www.opensource.org/licenses/apache2.0.php
//
//  You may elect to redistribute this code under either of these licenses.
//  ========================================================================
//

package org.eclipse.jetty.io;

import java.nio.ByteBuffer;
import java.util.concurrent.atomic.AtomicInteger;

import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Retainable;

A Retainable ByteBuffer.

Acquires a ByteBuffer from a ByteBufferPool and maintains a reference count that is initially 1, incremented with retain() and decremented with release(). The buffer is released to the pool when the reference count is decremented to 0.

/** * A Retainable ByteBuffer. * <p>Acquires a ByteBuffer from a {@link ByteBufferPool} and maintains a reference count that is * initially 1, incremented with {@link #retain()} and decremented with {@link #release()}. The buffer * is released to the pool when the reference count is decremented to 0.</p> */
public class RetainableByteBuffer implements Retainable { private final ByteBufferPool pool; private final ByteBuffer buffer; private final AtomicInteger references; public RetainableByteBuffer(ByteBufferPool pool, int size) { this(pool, size, false); } public RetainableByteBuffer(ByteBufferPool pool, int size, boolean direct) { this.pool = pool; this.buffer = pool.acquire(size, direct); this.references = new AtomicInteger(1); } public ByteBuffer getBuffer() { return buffer; } public int getReferences() { return references.get(); } @Override public void retain() { while (true) { int r = references.get(); if (r == 0) throw new IllegalStateException("released " + this); if (references.compareAndSet(r, r + 1)) break; } } public int release() { int ref = references.decrementAndGet(); if (ref == 0) pool.release(buffer); else if (ref < 0) throw new IllegalStateException("already released " + this); return ref; } public boolean hasRemaining() { return buffer.hasRemaining(); } public boolean isEmpty() { return !buffer.hasRemaining(); } @Override public String toString() { return String.format("%s@%x{%s,r=%d}", getClass().getSimpleName(), hashCode(), BufferUtil.toDetailString(buffer), getReferences()); } }