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

io.datakernel.csp.process.ChannelBifurcator 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!
package io.datakernel.csp.process;

import io.datakernel.csp.AbstractCommunicatingProcess;
import io.datakernel.csp.ChannelConsumer;
import io.datakernel.csp.ChannelInput;
import io.datakernel.csp.ChannelSupplier;
import io.datakernel.csp.dsl.WithChannelInput;

import static io.datakernel.common.Preconditions.checkState;
import static io.datakernel.common.Recyclable.tryRecycle;
import static io.datakernel.common.Sliceable.trySlice;
import static io.datakernel.eventloop.Eventloop.getCurrentEventloop;

/**
 * Communicating process which distributes
 * an input item to two output channels.
 *
 * @since 3.0.0
 */
//[START REGION_1]
public class ChannelBifurcator extends AbstractCommunicatingProcess
		implements WithChannelInput, T> {

	ChannelConsumer first;
	ChannelConsumer second;

	ChannelSupplier input;

	private ChannelBifurcator() {
	}

	public static  ChannelBifurcator create() {
		return new ChannelBifurcator<>();
	}

	// TODO: change constructor, I am just lazy pig to provide more that two output sources.
	public static  ChannelBifurcator create(ChannelSupplier supplier, ChannelConsumer first, ChannelConsumer second) {
		return new ChannelBifurcator().withInput(supplier).withOutputs(first, second);
	}

	//[END REGION_1]

	/**
	 * Provides ability to create a Bifurcator in the following way:
	 * {@code  bifurcator = ChannelBifurcator.create().withInput(i).withOutputs(o1, o2); }
	 */
	//[START REGION_2]
	public ChannelBifurcator withOutputs(ChannelConsumer firstOutput, ChannelConsumer secondOutput) {
		this.first = sanitize(firstOutput);
		this.second = sanitize(secondOutput);
		tryStart();
		return this;
	}
	//[END REGION_2]

	/**
	 * Bifurcator startup.
	 */
	//[START REGION_6]
	private void tryStart() {
		if (input != null && first != null && second != null) {
			getCurrentEventloop().post(this::startProcess);
		}
	}
	//[END REGION_6]

	/**
	 * Main process for our bifurcator.
	 * On every tick bifurcator (BF) checks if input item exists.
	 * If item exists, BF tries to send it to the output channels
	 * and continues listening to the input channel.
	 * 

* Note : if an item can be sliced into chunks, * bifurcator will try to slice the input item * before it is accepted by the output consumer. */ //[START REGION_4] @Override protected void doProcess() { if (isProcessComplete()) { return; } input.get() .whenComplete((item, e) -> { if (item != null) { first.accept(trySlice(item)).both(second.accept(trySlice(item))) .whenComplete(($, e1) -> { if (e1 == null) { doProcess(); } else { close(e1); } }); tryRecycle(item); } else { first.accept(null).both(second.accept(null)) .whenComplete(($, e2) -> completeProcess(e2)); } }); } //[END REGION_4] /** * Closes all channels. * * @param e an exception thrown on closing */ //[START REGION_5] @Override protected void doClose(Throwable e) { input.close(e); first.close(e); second.close(e); } //[END REGION_5] //[START REGION_3] @Override public ChannelInput getInput() { return input -> { checkState(!isProcessStarted(), "Can't configure bifurcator while it is running"); this.input = sanitize(input); tryStart(); return getProcessCompletion(); }; } //[END REGION_3] }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy