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

juzu.io.ChunkBuffer Maven / Gradle / Ivy

/*
 * Copyright 2013 eXo Platform SAS
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package juzu.io;

import java.io.IOException;
import java.util.LinkedList;

/** @author Julien Viet */
public class ChunkBuffer implements Streamable, Appendable {


  /** . */
  private static final int STATUS_BUFFERING = 0;

  /** . */
  private static final int STATUS_PROVIDING = 1;

  /** . */
  private static final int STATUS_CLOSED = 2;

  /** . */
  private final LinkedList queue = new LinkedList();

  /** . */
  private Stream consumer = null;

  /** . */
  private int status = STATUS_BUFFERING;

  /** . */
  private final Object lock = new Object();

  /** . */
  private Thread.UncaughtExceptionHandler errorHandler;

  public ChunkBuffer() {
  }

  public ChunkBuffer(Thread.UncaughtExceptionHandler errorHandler) {
    this.errorHandler = errorHandler;
  }

  public Appendable append(CharSequence csq) throws IOException {
    return append(Chunk.create(csq));
  }

  public Appendable append(CharSequence csq, int start, int end) throws IOException {
    return append(Chunk.create(csq));
  }

  public Appendable append(char c) throws IOException {
    return append(Chunk.create(c));
  }

  public ChunkBuffer append(Iterable chunks) {
    for (Chunk chunk : chunks) {
      append(chunk);
    }
    return this;
  }

  public ChunkBuffer append(Chunk chunk) {
    synchronized (lock) {
      switch (status) {
        case STATUS_CLOSED:
          throw new IllegalArgumentException("Already closed");
        case STATUS_BUFFERING:
          queue.add(chunk);
          break;
        case STATUS_PROVIDING:
          consumer.provide(chunk);
          break;
      }
    }
    return this;
  }

  public void send(Stream stream) {

    //
    synchronized (lock) {
      if (this.consumer != null) {
        throw new IllegalStateException("Already consumed");
      } else {
        this.consumer = stream;
      }
    }

    //
    boolean close;
    while (true) {
      Chunk chunk;
      synchronized (lock) {
        if (queue.isEmpty()) {
          if (status == STATUS_CLOSED) {
            close = true;
          } else {
            status = STATUS_PROVIDING;
            close = false;
          }
          break;
        } else {
          chunk = queue.removeFirst();
        }
      }
      stream.provide(chunk);
    }

    //
    if (close) {
      stream.close(errorHandler);
    }
  }

  public ChunkBuffer close() {
    Stream stream;
    synchronized (lock) {
      switch (status) {
        case STATUS_CLOSED:
          stream = null;
          break;
        case STATUS_PROVIDING:
          stream = this.consumer;
          status = STATUS_CLOSED;
          break;
        case STATUS_BUFFERING:
          stream = null;
          status = STATUS_CLOSED;
          break;
        default:
          throw new UnsupportedOperationException();
      }
    }
    if (stream != null) {
      stream.close(errorHandler);
    }
    return this;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy