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

io.datakernel.stream.processor.StreamMap Maven / Gradle / Ivy

Go to download

Composable asynchronous/reactive streams with powerful data processing capabilities.

The newest version!
/*
 * Copyright (C) 2015 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.stream.processor;

import io.datakernel.eventloop.Eventloop;
import io.datakernel.stream.AbstractStreamTransformer_1_1_Stateless;
import io.datakernel.stream.StreamDataReceiver;

import static com.google.common.base.Preconditions.checkNotNull;

/**
 * Provides to create some MapperProjection which will change received data, and send it to the
 * destination. It is {@link AbstractStreamTransformer_1_1_Stateless} which receives original
 * data and streams changed data.
 *
 * @param  type of input data
 * @param  type of output data
 */
public final class StreamMap extends AbstractStreamTransformer_1_1_Stateless implements StreamDataReceiver, StreamMapMBean {
	private int jmxItems;

	/**
	 * Primary interface which does mapping
	 *
	 * @param  type of input data
	 * @param  type of output data
	 */
	public interface Mapper {
		/**
		 * Holds mapping and streams it to destination
		 *
		 * @param input  received item
		 * @param output callback for streaming it to destination
		 */
		void map(I input, StreamDataReceiver output);
	}

	/**
	 * Map data with method apply and sends it to the destination
	 *
	 * @param  type of input data
	 * @param  type of output data
	 */
	public static abstract class MapperProjection implements Mapper {
		/**
		 * It contains operations which will be done for mapping
		 *
		 * @param input received data
		 * @return mapped object
		 */
		protected abstract O apply(I input);

		@Override
		public final void map(I input, StreamDataReceiver output) {
			O result = apply(input);
			output.onData(result);
		}
	}

	/**
	 * Filter which can map only that data which returns true in the method apply(), and sends it
	 * to the destination
	 *
	 * @param  type of input data
	 */
	public static abstract class MapperFilter implements Mapper {
		/**
		 * It contains some boolean expression. It resolves or does not resolves sending
		 * this data to destination
		 *
		 * @param input received data
		 * @return true, if this item must be sending, false else
		 */
		protected abstract boolean apply(I input);

		@Override
		public final void map(I input, StreamDataReceiver output) {
			if (apply(input)) {
				output.onData(input);
			}
		}
	}

	/**
	 * Provides use two mappers in one time.
	 *
	 * @param  type of input data for first mapper
	 * @param  type of output data for first mapper if type of input data for second filter
	 * @param  type of output data of second filter
	 * @return new mapper which is composition from two mappers from arguments
	 */
	public static  Mapper combine(final Mapper mapper1, final Mapper mapper2) {
		return new Mapper() {
			@Override
			public void map(I input, final StreamDataReceiver output) {
				mapper1.map(input, new StreamDataReceiver() {
					@Override
					public void onData(T item) {
						mapper2.map(item, output);
					}
				});
			}
		};
	}

	private final Mapper mapper;

	/**
	 * Creates a new instance of stream map
	 *
	 * @param eventloop eventloop in which runs StreamMap
	 * @param mapper    mapper for applying to input data
	 */
	public StreamMap(Eventloop eventloop, Mapper mapper) {
		super(eventloop);
		this.mapper = checkNotNull(mapper);
	}

	/**
	 * Always return this object
	 */
	@SuppressWarnings("unchecked")
	@Override
	public StreamDataReceiver getDataReceiver() {
		return this;
	}

	/**
	 * Changes input data and receive it to the destination
	 *
	 * @param item received data
	 */
	@Override
	public void onData(I item) {
		assert jmxItems != ++jmxItems;
		mapper.map(item, downstreamDataReceiver);
	}

	@Override
	public int getItems() {
		return jmxItems;
	}

	@SuppressWarnings("AssertWithSideEffects")
	@Override
	public String toString() {
		String items = "?";
		assert (items = "" + jmxItems) != null;
		return '{' + super.toString() + " items:" + items + '}';
	}
}