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

io.datakernel.csp.ChannelSupplier Maven / Gradle / Ivy

Go to download

Communicating sequential process via channels, similar to Golang's channels. A channel could be imagine as a pipe which connects some processes.

The newest version!
/*
 * Copyright (C) 2015-2019 SoftIndex LLC.
 *
 * 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 io.datakernel.csp;

import io.datakernel.async.function.AsyncSupplier;
import io.datakernel.async.process.AsyncExecutor;
import io.datakernel.async.process.Cancellable;
import io.datakernel.bytebuf.ByteBuf;
import io.datakernel.common.exception.UncheckedException;
import io.datakernel.csp.dsl.ChannelSupplierTransformer;
import io.datakernel.csp.queue.ChannelQueue;
import io.datakernel.net.AsyncTcpSocket;
import io.datakernel.promise.Promise;
import io.datakernel.promise.SettablePromise;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.Iterator;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static io.datakernel.common.Recyclable.tryRecycle;
import static io.datakernel.common.collection.CollectionUtils.asIterator;

/**
 * This interface represents supplier of {@link Promise} of data that should be used serially
 * (each consecutive {@link #get()}) operation should be called only after previous
 * {@link #get()} operation finishes.
 * 

* After supplier is closed, all subsequent calls to {@link #get()} will return promise, * completed exceptionally. *

* If any exception is caught while supplying data items, {@link #close(Throwable)} method * should be called. All resources should be freed and the caught exception should be * propagated to all related processes. *

* If {@link #get()} returns {@link Promise} of {@code null}, it represents end-of-stream * and means that no additional data should be queried. */ public interface ChannelSupplier extends Cancellable { @NotNull Promise get(); /** * @see #of(AsyncSupplier, Cancellable) */ static ChannelSupplier of(AsyncSupplier supplier) { return of(supplier, null); } /** * Wraps {@link AsyncSupplier} in ChannelSupplier, when {@code get()} * is called, {@code AsyncSupplier}'s {@code get()} will be executed. * * @param supplier an {@code AsyncSupplier} to be wrapped in ChannelSupplier * @param cancellable a {@code Cancellable} which will be set * for the ChannelSupplier wrapper * @param data type wrapped in {@code AsyncSupplier} and ChannelSupplier * @return ChannelSupplier which wraps {@code AsyncSupplier} */ static ChannelSupplier of(AsyncSupplier supplier, @Nullable Cancellable cancellable) { return new AbstractChannelSupplier(cancellable) { @Override protected Promise doGet() { return supplier.get(); } }; } /** * Returns a ChannelSupplier received from {@link ChannelQueue}. */ static ChannelSupplier ofConsumer(Consumer> consumer, ChannelQueue queue) { consumer.accept(queue.getConsumer()); return queue.getSupplier(); } /** * Wraps provided default {@link Supplier} to ChannelSupplier. */ static ChannelSupplier ofSupplier(Supplier> supplier) { return of(supplier::get); } /** * Returns a {@link ChannelSuppliers.ChannelSupplierEmpty}. */ static ChannelSupplier of() { return new ChannelSuppliers.ChannelSupplierEmpty<>(); } /** * Wraps provided {@code value} to a {@link ChannelSuppliers.ChannelSupplierOfValue}. * * @param value a value to be wrapped in ChannelSupplier * @return a {@code ChannelSupplierOfValue} which wraps the {@code value} */ static ChannelSupplier of(T value) { return new ChannelSuppliers.ChannelSupplierOfValue<>(value); } /** * @see #ofIterator(Iterator) */ @SafeVarargs static ChannelSupplier of(T... values) { return ofIterator(asIterator(values)); } /** * Returns a {@link ChannelSuppliers.ChannelSupplierOfException} * of provided exception. * * @param e a {@link Throwable} to be wrapped in ChannelSupplier */ static ChannelSupplier ofException(Throwable e) { return new ChannelSuppliers.ChannelSupplierOfException<>(e); } /** * @see #ofIterator(Iterator) */ static ChannelSupplier ofIterable(Iterable iterable) { return ofIterator(iterable.iterator()); } /** * @see #ofIterator(Iterator) */ static ChannelSupplier ofStream(Stream stream) { return ofIterator(stream.iterator()); } /** * Wraps provided {@code Iterator} into * {@link ChannelSuppliers.ChannelSupplierOfIterator}. * * @param iterator an iterator to be wrapped in ChannelSupplier * @return a ChannelSupplier which wraps elements of type */ static ChannelSupplier ofIterator(Iterator iterator) { return new ChannelSuppliers.ChannelSupplierOfIterator<>(iterator); } /** * Wraps {@link AsyncTcpSocket#read()} operation into {@link ChannelSupplier} * * @return {@link ChannelSupplier} of ByteBufs that are read from network */ static ChannelSupplier ofSocket(AsyncTcpSocket socket) { return ChannelSuppliers.prefetch(ChannelSupplier.of(socket::read, socket)); } /** * Wraps {@code promise} of ChannelSupplier in ChannelSupplier or * returns the ChannelSupplier from {@code promise} itself. *

* If {@code promise} is completed, it will be materialized and its result * (a ChannelSupplier) will be returned. *

* Otherwise, when {@code get()} is called, it will wait until {@code promise} * completes and {@code promise} result's (a ChannelSupplier) {@code get()} * operation will be executed. If the {@code promise} completes exceptionally, * a {@code promise} of exception will be returned. * * @param promise wraps a {@code ChannelSupplier} * @return a ChannelSupplier of {@code promise} or a wrapper ChannelSupplier */ static ChannelSupplier ofPromise(Promise> promise) { if (promise.isResult()) return promise.getResult(); return new AbstractChannelSupplier() { ChannelSupplier supplier; Throwable exception; @Override protected Promise doGet() { if (supplier != null) return supplier.get(); return promise.thenEx((supplier, e) -> { if (e == null) { this.supplier = supplier; return supplier.get(); } else { return Promise.ofException(e); } }); } @Override protected void onClosed(@NotNull Throwable e) { exception = e; promise.whenResult(supplier -> supplier.close(e)); } }; } /** * Returns a {@code ChannelSupplier} wrapped in {@link Supplier} * and calls its {@code get()} when {@code get()} method is called. * * @param provider a provider of {@code ChannelSupplier} * @return a {@code ChannelSupplier} that was wrapped in * the {@code provider} */ static ChannelSupplier ofLazyProvider(Supplier> provider) { return new AbstractChannelSupplier() { private ChannelSupplier supplier; @Override protected Promise doGet() { if (supplier == null) supplier = provider.get(); return supplier.get(); } @Override protected void onClosed(@NotNull Throwable e) { if (supplier != null) { supplier.close(e); } } }; } /** * Transforms this ChannelSupplier with the provided {@code fn}. * * @param returned result after transformation * @param fn {@link ChannelSupplierTransformer} applied to the ChannelSupplier */ default R transformWith(ChannelSupplierTransformer fn) { return fn.transform(this); } /** * Creates and returns a new {@link AbstractChannelSupplier} * based on current ChannelSupplier and makes its promise * complete asynchronously. */ default ChannelSupplier async() { return new AbstractChannelSupplier(this) { @Override protected Promise doGet() { return ChannelSupplier.this.get().async(); } }; } /** * Creates and returns a new {@link AbstractChannelSupplier} * based on current ChannelSupplier and makes its promise * executed by the provided {@code asyncExecutor}. */ default ChannelSupplier withExecutor(AsyncExecutor asyncExecutor) { return new AbstractChannelSupplier(this) { @Override protected Promise doGet() { return asyncExecutor.execute(ChannelSupplier.this::get); } }; } /** * Creates and returns a new {@link AbstractChannelSupplier} * based on current ChannelSupplier and when its Promise completes * successfully, the result is accepted by the provided {@code fn}. */ default ChannelSupplier peek(Consumer fn) { return new AbstractChannelSupplier(this) { @Override protected Promise doGet() { return ChannelSupplier.this.get() .whenResult(value -> { if (value != null) fn.accept(value);}); } }; } /** * Creates and returns a new {@link AbstractChannelSupplier} * based on current ChannelSupplier and when its Promise completes, * applies provided {@code fn} to the result. */ default ChannelSupplier map(Function fn) { return new AbstractChannelSupplier(this) { @Override protected Promise doGet() { return ChannelSupplier.this.get() .map(value -> { if (value != null) { try { return fn.apply(value); } catch (UncheckedException u) { ChannelSupplier.this.close(u.getCause()); throw u; } } else { return null; } }); } }; } /** * Creates and returns a new {@link AbstractChannelSupplier} * based on current ChannelSupplier and applies provided {@code fn} * to its Promise asynchronously. */ default ChannelSupplier mapAsync(Function> fn) { return new AbstractChannelSupplier(this) { @Override protected Promise doGet() { return ChannelSupplier.this.get() .then(value -> value != null ? fn.apply(value) : Promise.of(null)); } }; } /** * Creates and returns a new {@link AbstractChannelSupplier} * based on current ChannelSupplier and checks if its Promise's value(s) * match(es) the predicate, leaving only those value(s) which pass the test. */ default ChannelSupplier filter(Predicate predicate) { return new AbstractChannelSupplier(this) { @Override protected Promise doGet() { while (true) { Promise promise = ChannelSupplier.this.get(); if (promise.isResult()) { T value = promise.getResult(); if (value == null || predicate.test(value)) return promise; tryRecycle(value); continue; } return promise.then(value -> { if (value == null || predicate.test(value)) { return Promise.of(value); } else { tryRecycle(value); return get(); } }); } } }; } /** * Creates and returns a new {@link AbstractChannelSupplier} based on current * ChannelSupplier, when its {@code get} is called, its values will be returned * until they don't fit the {@code predicate}. If one of the results passed the * {@code predicate test}, consequent {@code get} operations will return {@code null}. */ default ChannelSupplier until(Predicate predicate) { return new AbstractChannelSupplier(this) { boolean stop = false; @Override protected Promise doGet() { if (stop) { return Promise.of(null); } return ChannelSupplier.this.get() .map(value -> { if (value == null) { return null; } if (predicate.test(value)) { stop = true; } return value; }); } }; } /** * Creates and returns a new {@link AbstractChannelSupplier} * based on current ChannelSupplier. Even if its Promise completes * with an exception, {@code get()} method will return a successfully * completed Promise (in case of exception, with {@code null} result value). */ default ChannelSupplier lenient() { return new AbstractChannelSupplier(this) { @Override protected Promise doGet() { return ChannelSupplier.this.get().thenEx((value, e) -> Promise.of(value)); } }; } /** * @see ChannelSuppliers#streamTo(ChannelSupplier, ChannelConsumer) */ default Promise streamTo(ChannelConsumer consumer) { return ChannelSuppliers.streamTo(this, consumer); } default Promise streamTo(Promise> consumer) { return ChannelSuppliers.streamTo(this, ChannelConsumer.ofPromise(consumer)); } /** * Binds this ChannelSupplier to provided {@link ChannelInput} */ default Promise bindTo(ChannelInput to) { return to.set(this); } /** * @see ChannelSuppliers#collect */ default Promise toCollector(Collector collector) { return ChannelSuppliers.collect(this, collector.supplier().get(), collector.accumulator(), collector.finisher()); } /** * @see #toCollector(Collector) */ default Promise> toList() { return toCollector(Collectors.toList()); } default ChannelSupplier withEndOfStream(Function, Promise> fn) { SettablePromise endOfStream = new SettablePromise<>(); Promise newEndOfStream = fn.apply(endOfStream); return new AbstractChannelSupplier(this) { @SuppressWarnings("unchecked") @Override protected Promise doGet() { return ChannelSupplier.this.get() .thenEx((item, e) -> { if (e == null) { if (item != null) return Promise.of(item); endOfStream.trySet(null); return (Promise) newEndOfStream; } else { endOfStream.trySetException(e); return (Promise) newEndOfStream; } }); } @Override protected void onClosed(@NotNull Throwable e) { endOfStream.trySetException(e); } }; } static Promise getEndOfStream(Consumer, Promise>> fn) { return Promise.ofCallback(cb -> fn.accept(endOfStream -> endOfStream.whenComplete(cb))); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy