All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.yahoo.jdisc.handler.BufferedContentChannel Maven / Gradle / Ivy

// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.jdisc.handler;

import java.nio.ByteBuffer;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;

/**
 * This class implements an unlimited, non-blocking content queue. All {@link ContentChannel} methods are implemented
 * by pushing to a thread-safe internal queue. All of the queued calls are forwarded to another ContentChannel when
 * {@link #connectTo(ContentChannel)} is called. Once connected, this class becomes a non-buffering proxy for the
 * connected ContentChannel.
 *
 * @author Simon Thoresen Hult
 */
public final class BufferedContentChannel implements ContentChannel {

    private final Object lock = new Object();
    private List queue = new LinkedList<>();
    private ContentChannel content = null;
    private boolean closed = false;
    private CompletionHandler closeCompletion = null;

    /**
     * 

Connects this BufferedContentChannel to a ContentChannel. First, this method forwards all queued calls to the * connected ContentChannel. Once this method has been called, all future calls to {@link #write(ByteBuffer, * CompletionHandler)} and {@link #close(CompletionHandler)} are synchronously forwarded to the connected * ContentChannel.

* * @param content The ContentChannel to connect to. * @throws NullPointerException If the content argument is null. * @throws IllegalStateException If another ContentChannel has already been connected. */ public void connectTo(ContentChannel content) { Objects.requireNonNull(content, "content"); boolean closed; List queue; synchronized (lock) { if (this.content != null || this.queue == null) { throw new IllegalStateException(); } closed = this.closed; queue = this.queue; this.queue = null; } for (Entry entry : queue) { content.write(entry.buf, entry.handler); } if (closed) { content.close(closeCompletion); } synchronized (lock) { this.content = content; lock.notifyAll(); } } /** *

Returns whether or not {@link #connectTo(ContentChannel)} has been called. Even if this method returns false, * calling {@link #connectTo(ContentChannel)} might still throw an IllegalStateException if there is a race.

* * @return True if {@link #connectTo(ContentChannel)} has been called. */ public boolean isConnected() { synchronized (lock) { return content != null; } } /** *

Creates a {@link ReadableContentChannel} and {@link #connectTo(ContentChannel) connects} to it.

* * @return The new ReadableContentChannel that this connected to. */ public ReadableContentChannel toReadable() { ReadableContentChannel ret = new ReadableContentChannel(); connectTo(ret); return ret; } /** *

Creates a {@link ContentInputStream} and {@link #connectTo(ContentChannel) connects} to its internal * ContentChannel.

* * @return The new ContentInputStream that this connected to. */ public ContentInputStream toStream() { return toReadable().toStream(); } @Override public void write(ByteBuffer buf, CompletionHandler handler) { ContentChannel content; synchronized (lock) { if (closed) { throw new IllegalStateException(); } if (queue != null) { queue.add(new Entry(buf, handler)); return; } try { while (this.content == null) { lock.wait(); // waiting for connecTo() } } catch (InterruptedException e) { throw new IllegalStateException(e); } if (closed) { throw new IllegalStateException(); } content = this.content; } content.write(buf, handler); } @Override public void close(CompletionHandler handler) { ContentChannel content; synchronized (lock) { if (closed) { throw new IllegalStateException(); } if (queue != null) { closed = true; closeCompletion = handler; return; } try { while (this.content == null) { lock.wait(); // waiting for connecTo() } } catch (InterruptedException e) { throw new IllegalStateException(e); } if (closed) { throw new IllegalStateException(); } closed = true; content = this.content; } content.close(handler); } private static class Entry { final ByteBuffer buf; final CompletionHandler handler; Entry(ByteBuffer buf, CompletionHandler handler) { this.handler = handler; this.buf = buf; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy