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

io.vertx.ext.reactivestreams.impl.ReactiveReadStreamImpl Maven / Gradle / Ivy

There is a newer version: 5.0.0.CR3
Show newest version
/*
 * Copyright 2014 Red Hat, Inc.
 *
 *  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 io.vertx.ext.reactivestreams.impl;

import io.vertx.core.Handler;
import io.vertx.ext.reactivestreams.ReactiveReadStream;
import org.reactivestreams.Subscription;

import java.util.ArrayDeque;
import java.util.Queue;

/**
 * @author Nick Scavelli
 * @author Tim Fox
 */
public class ReactiveReadStreamImpl implements ReactiveReadStream {

  private final long batchSize;
  private Handler dataHandler;
  private Handler endHandler;
  private Handler exceptionHandler;

  private Subscription subscription;
  private final Queue pending = new ArrayDeque<>();
  private long demand = Long.MAX_VALUE;
  private long tokens;

  public ReactiveReadStreamImpl(long batchSize) {
    this.batchSize = batchSize;
  }

  public synchronized ReactiveReadStream handler(Handler handler) {
    this.dataHandler = handler;
    if (dataHandler != null && demand > 0L) {
      checkRequestTokens();
    }
    return this;
  }

  @Override
  public synchronized ReactiveReadStream pause() {
    this.demand = 0L;
    return this;
  }

  @Override
  public ReactiveReadStream fetch(long amount) {
    if (amount > 0L) {
      demand += amount;
      if (demand < 0L) {
        demand = Long.MAX_VALUE;
      }
      T data;
      while (demand > 0L && (data = pending.poll()) != null) {
        if (demand != Long.MAX_VALUE) {
          demand--;
        }
        handleData(data);
      }
      checkRequestTokens();
    }
    return this;
  }

  @Override
  public synchronized ReactiveReadStream resume() {
    return fetch(Long.MAX_VALUE);
  }

  @Override
  public synchronized ReactiveReadStream endHandler(Handler endHandler) {
    this.endHandler = endHandler;
    return this;
  }

  @Override
  public synchronized ReactiveReadStream exceptionHandler(Handler handler) {
    this.exceptionHandler = handler;
    return this;
  }

  @Override
  public synchronized void onSubscribe(Subscription subscription) {
    if (subscription == null) {
      throw new NullPointerException("subscription");
    }
    if (this.subscription != null) {
      subscription.cancel();
    } else {
      this.subscription = subscription;
    }
  }

  @Override
  public synchronized void onNext(T data) {
    if (data == null) {
      throw new NullPointerException("data");
    }
    checkUnsolicitedTokens();
    if (demand > 0L) {
      if (demand != Long.MAX_VALUE) {
        demand--;
      }
      if (pending.size() > 0) {
        pending.add(data);
        data = pending.poll();
      }
      handleData(data);
    } else {
      pending.add(data);
    }
  }

  @Override
  public synchronized void onError(Throwable throwable) {
    if (throwable == null) {
      throw new NullPointerException("throwable");
    }
    if (exceptionHandler != null) {
      exceptionHandler.handle(throwable);
    }
  }

  @Override
  public synchronized void onComplete() {
    if (endHandler != null) {
      endHandler.handle(null);
    }
  }

  protected void checkUnsolicitedTokens() {
    if (tokens == 0) {
      throw new IllegalStateException("Data received but wasn't requested");
    }
  }

  private synchronized void handleData(T data) {
    if (dataHandler != null) {
      dataHandler.handle(data);
      tokens--;
      checkRequestTokens();
    }
  }

  private void checkRequestTokens() {
    if (demand > 0L && subscription != null && tokens == 0) {
      tokens = batchSize;
      subscription.request(batchSize);
    }
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy