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

io.datakernel.datastream.StreamConsumer Maven / Gradle / Ivy

/*
 * Copyright (C) 2015-2018 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.datastream;

import io.datakernel.async.process.Cancellable;
import io.datakernel.csp.AbstractChannelConsumer;
import io.datakernel.csp.ChannelConsumer;
import io.datakernel.datastream.StreamConsumers.ClosingWithErrorImpl;
import io.datakernel.datastream.StreamConsumers.Idle;
import io.datakernel.datastream.StreamConsumers.OfChannelConsumerImpl;
import io.datakernel.datastream.StreamConsumers.Skip;
import io.datakernel.datastream.processor.StreamLateBinder;
import io.datakernel.datastream.processor.StreamTransformer;
import io.datakernel.promise.Promise;

import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Function;

import static io.datakernel.common.Preconditions.checkArgument;
import static io.datakernel.datastream.StreamCapability.LATE_BINDING;

/**
 * It represents an object which can asynchronous receive streams of data.
 * Implementors of this interface are strongly encouraged to extend one of the abstract classes
 * in this package which implement this interface and make the threading and state management
 * easier.
 */
public interface StreamConsumer extends Cancellable {
	/**
	 * Sets wired supplier. It will sent data to this consumer
	 *
	 * @param supplier stream supplier for setting
	 */
	void setSupplier(StreamSupplier supplier);

	Promise getAcknowledgement();

	Set getCapabilities();

	static  StreamConsumer idle() {
		return new Idle<>();
	}

	static  StreamConsumer skip() {
		return new Skip<>();
	}

	/**
	 * @deprecated use of this consumer is discouraged as it breaks the whole asynchronous model.
	 * Exists only for testing
	 */
	@Deprecated
	static  StreamConsumer of(Consumer consumer) {
		return new StreamConsumers.OfConsumerImpl<>(consumer);
	}

	static  StreamConsumer closingWithError(Throwable e) {
		return new ClosingWithErrorImpl<>(e);
	}

	static  StreamConsumer ofChannelConsumer(ChannelConsumer consumer) {
		return new OfChannelConsumerImpl<>(consumer);
	}

	static  StreamConsumer ofSupplier(Function, Promise> supplier) {
		StreamTransformer forwarder = StreamTransformer.identity();
		Promise extraAcknowledge = supplier.apply(forwarder.getOutput());
		StreamConsumer result = forwarder.getInput();
		if (extraAcknowledge == Promise.complete()) return result;
		return result
				.withAcknowledgement(ack -> ack.both(extraAcknowledge));
	}

	default  R transformWith(StreamConsumerTransformer fn) {
		return fn.transform(this);
	}

	default StreamConsumer withLateBinding() {
		return getCapabilities().contains(LATE_BINDING) ? this : transformWith(StreamLateBinder.create());
	}

	default ChannelConsumer asSerialConsumer() {
		StreamSupplierEndpoint endpoint = new StreamSupplierEndpoint<>();
		endpoint.streamTo(this);
		return new AbstractChannelConsumer(this) {
			@Override
			protected Promise doAccept(T item) {
				if (item != null) return endpoint.put(item);
				assert endpoint.getConsumer() != null;
				return endpoint.put(null).both(endpoint.getConsumer().getAcknowledgement());
			}
		};
	}

	String LATE_BINDING_ERROR_MESSAGE = "" +
			"StreamConsumer %s does not have LATE_BINDING capabilities, " +
			"it must be bound in the same tick when it is created. " +
			"Alternatively, use .withLateBinding() modifier";

	static  StreamConsumer ofPromise(Promise> promise) {
		if (promise.isResult()) return promise.getResult();
		StreamLateBinder lateBounder = StreamLateBinder.create();
		promise.whenComplete((consumer, e) -> {
			if (e == null) {
				checkArgument(consumer.getCapabilities().contains(LATE_BINDING),
						LATE_BINDING_ERROR_MESSAGE, consumer);
				lateBounder.getOutput().streamTo(consumer);
			} else {
				lateBounder.getOutput().streamTo(closingWithError(e));
			}
		});
		return lateBounder.getInput();
	}

	default StreamConsumer withAcknowledgement(Function, Promise> fn) {
		Promise acknowledgement = getAcknowledgement();
		Promise suppliedAcknowledgement = fn.apply(acknowledgement);
		if (acknowledgement == suppliedAcknowledgement) return this;
		Promise newAcknowledgement = suppliedAcknowledgement;
		return new ForwardingStreamConsumer(this) {
			@Override
			public Promise getAcknowledgement() {
				return newAcknowledgement;
			}
		};
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy