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

io.datakernel.csp.process.AbstractChannelTransformer 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-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.csp.process;

import io.datakernel.csp.*;
import io.datakernel.csp.dsl.WithChannelTransformer;
import io.datakernel.promise.Promise;

import static io.datakernel.common.Preconditions.checkState;

public abstract class AbstractChannelTransformer, I, O>
		extends AbstractCommunicatingProcess
		implements WithChannelTransformer {
	protected ChannelSupplier input;
	protected ChannelConsumer output;

	protected final Promise send(O item) {
		return output.accept(item);
	}

	protected final Promise sendEndOfStream() {
		return output.accept(null);
	}

	protected abstract Promise onItem(I item);

	protected Promise onProcessFinish() {
		return sendEndOfStream();
	}

	protected Promise onProcessStart() {
		return Promise.complete();
	}

	@Override
	protected void beforeProcess() {
		checkState(input != null, "Input was not set");
		checkState(output != null, "Output was not set");
	}

	@Override
	protected void doProcess() {
		onProcessStart()
				.whenComplete(($, e) -> {
					if (e == null) {
						loop();
					} else {
						close(e);
					}
				});
	}

	private void loop() {
		input.get()
				.then(item ->
						item != null ?
								onItem(item)
										.whenResult($ -> loop()) :
								onProcessFinish()
										.whenResult($ -> completeProcess()))
				.whenException(this::close);
	}

	@SuppressWarnings("ConstantConditions")
	@Override
	public ChannelInput getInput() {
		return input -> {
			this.input = sanitize(input);
			if (this.input != null && this.output != null) startProcess();
			return getProcessCompletion();
		};
	}

	@SuppressWarnings("ConstantConditions")
	@Override
	public ChannelOutput getOutput() {
		return output -> {
			this.output = sanitize(output);
			if (this.input != null && this.output != null) startProcess();
		};
	}

	@Override
	protected final void doClose(Throwable e) {
		input.close(e);
		output.close(e);
	}
}