com.github.tix320.kiwi.api.reactive.observable.Observable Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of kiwi Show documentation
Show all versions of kiwi Show documentation
Reactive programming library
package com.github.tix320.kiwi.api.reactive.observable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import com.github.tix320.kiwi.api.check.Try;
import com.github.tix320.kiwi.api.reactive.publisher.BufferPublisher;
import com.github.tix320.kiwi.api.reactive.publisher.SimplePublisher;
import com.github.tix320.kiwi.internal.reactive.observable.UnhandledObservableException;
import com.github.tix320.kiwi.internal.reactive.observable.transform.multiple.ConcatObservable;
import com.github.tix320.kiwi.internal.reactive.observable.transform.multiple.ZipObservable;
import com.github.tix320.kiwi.internal.reactive.observable.transform.single.WaitCompleteObservable;
import com.github.tix320.kiwi.internal.reactive.observable.transform.single.collect.JoinObservable;
import com.github.tix320.kiwi.internal.reactive.observable.transform.single.collect.ToListObservable;
import com.github.tix320.kiwi.internal.reactive.observable.transform.single.collect.ToMapObservable;
import com.github.tix320.kiwi.internal.reactive.observable.transform.single.operator.*;
/**
* @param type of data.
*
* @author Tigran Sargsyan on 21-Feb-19
*/
public interface Observable {
/**
* Subscribe to observable.
* If observable already completed, then available values will be processed immediately.
*
* @param consumer for processing items
*
* @return object, for controlling subscription in future
*/
default Subscription subscribe(Consumer consumer) {
return subscribe(consumer, throwable -> {
throw new UnhandledObservableException(throwable);
});
}
/**
* Subscribe to observable.
* If observable already completed, then available values will be processed immediately.
*
* @param consumer for processing items
* @param onComplete action on complete
*
* @return object, for controlling subscription in future
*/
default Subscription subscribe(Consumer consumer, Runnable onComplete) {
return subscribe(new Subscriber<>() {
@Override
public void onSubscribe(Subscription subscription) {
}
@Override
public boolean onPublish(T item) {
consumer.accept(item);
return true;
}
@Override
public boolean onError(Throwable throwable) {
throw new UnhandledObservableException(throwable);
}
@Override
public void onComplete() {
onComplete.run();
}
});
}
/**
* Subscribe to observable.
* If observable already completed, then available values will be processed immediately.
* If any error occurs, then errorHandler will be invoked.
*
* @param consumer for processing items
* @param errorHandler for handling errors
*
* @return object, for controlling subscription in future
*/
default Subscription subscribe(Consumer consumer, ConditionalConsumer errorHandler) {
return particularSubscribe(item -> {
consumer.accept(item);
return true;
}, errorHandler);
}
/**
* Subscribe to observable and handle every item, consumer must return boolean value,
* which indicates that need more elements or not.
* If observable already completed, then available values will be processed immediately.
*
* @param consumer for processing items
*
* @return object, for controlling subscription in future
*/
default Subscription particularSubscribe(ConditionalConsumer consumer) {
return particularSubscribe(consumer, throwable -> {
throw new UnhandledObservableException(throwable);
});
}
/**
* Subscribe to observable and handle every item, consumer must return boolean value,
* which indicates that need more elements or not.
* If observable already completed, then available values will be processed immediately.
* If any error occurs, then errorHandler will be invoked.
*
* @param consumer for processing items
* @param errorHandler for handling errors
*
* @return object, for controlling subscription in future
*/
default Subscription particularSubscribe(ConditionalConsumer consumer,
ConditionalConsumer errorHandler) {
return subscribe(new Subscriber<>() {
@Override
public void onSubscribe(Subscription subscription) {
}
@Override
public boolean onPublish(T item) {
return consumer.consume(item);
}
@Override
public boolean onError(Throwable throwable) {
return errorHandler.consume(throwable);
}
@Override
public void onComplete() {
}
});
}
/**
* Subscribe to observable and handle every item, error or completeness.
* If observable already completed, then available values will be processed immediately
* and after which completed handler will be invoked.
*
* @param subscriber for subscribing
*
* @return object, for controlling subscription in future
*/
Subscription subscribe(Subscriber subscriber);
/**
* Blocks current thread until this observable will be completed or will not want more items.
*/
default void blockUntilComplete() {
await().subscribe(t -> {});
}
/**
* Blocks current thread until this observable will be published one value and return.
*/
default T get() {
CountDownLatch latch = new CountDownLatch(1);
AtomicReference itemHolder = new AtomicReference<>();
this.toMono().subscribe(item -> {
itemHolder.set(item);
latch.countDown();
});
Try.runOrRethrow(latch::await);
return itemHolder.get();
}
// transforming functions --------------------------------------
/**
* Returns observable, which subscription will blocks thread until it will be completed or will not want more items.
*
* @return new observable
*/
default Observable await() {
return new WaitCompleteObservable<>(this);
}
/**
* Return observable, which will subscribe to this and receive n objects, after that unsubscribe.
*
* @param count for wanted objects
*
* @return new observable
*/
default Observable take(long count) {
return new CountingObservable<>(this, count);
}
/**
* Return observable, which will subscribe to given observable
* and unsubscribe from this observable, when given will be completed.
*
* @param observable to subscribe
*
* @return new observable
*/
default Observable takeUntil(Observable observable) {
return new UntilObservable<>(this, observable);
}
/**
* Equivalent to {@link Observable#take(long)} with value 1
*
* @return new observable {@link MonoObservable}
*/
default MonoObservable toMono() {
return new OnceObservable<>(this);
}
/**
* Return observable, which will subscribe to this and transform every object according to given transformer.
*
* @param mapper for transform objects
* @param type of result object
*
* @return new observable
*/
default Observable map(Function mapper) {
return new MapperObservable<>(this, mapper);
}
/**
* Return observable, which will subscribe to this and set filter to objects according to given filter.
*
* @param filter for filtering objects
*
* @return new observable
*/
default Observable filter(Predicate filter) {
return new FilterObservable<>(this, filter);
}
/**
* Return observable, which will subscribe to this and wait until it will be completed,
* and collect received values to map according to given factories.
*
* @param keyMapper for extracting map key from objects
* @param valueMapper for extracting map value from objects
* @param type of map key
* @param type of map value
*
* @return new observable
*/
default Observable