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

org.nasdanika.models.rules.Inspector Maven / Gradle / Ivy

package org.nasdanika.models.rules;

import java.util.Collection;
import java.util.function.BiConsumer;
import java.util.stream.Stream;

import org.nasdanika.capability.CapabilityLoader;
import org.nasdanika.capability.CapabilityProvider;
import org.nasdanika.capability.ServiceCapabilityFactory;
import org.nasdanika.common.Composeable;
import org.nasdanika.common.Context;
import org.nasdanika.common.ProgressMonitor;

/**
 * Inspects provided object and passes inspection results to a consumer
 */
public interface Inspector extends Composeable> {
		
	void inspect(T target, BiConsumer inspectionResultConsumer, Context context, ProgressMonitor progressMonitor);
	
	/**
	 * @param type
	 * @return true if the inspector "is interested" in targets of specific type and they shall be passed to it.
	 */
	boolean isForType(Class targetType);
	
	@Override
	default Inspector compose(Inspector other) {
		if (other == null) {
			return this;
		}
		
		return new Inspector() {

			@Override
			public void inspect(T target, BiConsumer inspectionResultConsumer, Context context, ProgressMonitor progressMonitor) {
				if (target != null) {
					if (Inspector.this.isForType(target.getClass())) {
						Inspector.this.inspect(target, inspectionResultConsumer, context, progressMonitor);
					}
					if (other.isForType(target.getClass())) {
						other.inspect(target, inspectionResultConsumer, context, progressMonitor);
					}
				}
				
			}

			@Override
			public boolean isForType(Class targetType) {				
				return Inspector.this.isForType(targetType) || other.isForType(targetType);
			}
		};
		
	}
	
	@SafeVarargs
	static  Inspector compose(Inspector... inspectors) {
		return new Inspector() {

			@Override
			public void inspect(T target, BiConsumer inspectionResultConsumer, Context context, ProgressMonitor progressMonitor) {
				if (target != null) {
					for (Inspector inspector: inspectors) {
						if (inspector.isForType(target.getClass())) {
							inspector.inspect(target, inspectionResultConsumer, context, progressMonitor);
						}
					}
				}				
			}

			@Override
			public boolean isForType(Class targetType) {
				for (Inspector inspector: inspectors) {
					if (inspector.isForType(targetType)) {
						return true;
					}
				}
				return false;
			}
		};
		
	}
	
	static  Inspector compose(Collection> inspectors, boolean parallel) {
		return new Inspector() {

			@Override
			public void inspect(T target, BiConsumer inspectionResultConsumer, Context context, ProgressMonitor progressMonitor) {
				if (target != null) {
					Stream> iStream = inspectors.stream();
					if (parallel) {
						iStream = iStream.parallel();
					}
					iStream.forEach(inspector -> inspector.inspect(target, inspectionResultConsumer, context, progressMonitor));
				}				
			}

			@Override
			public boolean isForType(Class targetType) {
				Stream> iStream = inspectors.stream();
				if (parallel) {
					iStream = iStream.parallel();
				}
				return iStream.filter(i -> i.isForType(targetType)).findAny().isPresent();
			}
		};		
	}
	
	static  Inspector nop() {
		return new Inspector() {

			@Override
			public void inspect(T target, BiConsumer inspectionResultConsumer, Context context, ProgressMonitor progressMonitor) {
				// NOP				
			}

			@Override
			public boolean isForType(Class targetType) {
				return false;
			}
			
		};
	}

	/**
	 * Loads inspectors from Inspector.Factory services and composes them.
	 * @return
	 */
	static Inspector load(Object requirement, ProgressMonitor progressMonitor) {
		Inspector ret = null;
		CapabilityLoader capabilityLoader = new CapabilityLoader();
		Iterable> providers = capabilityLoader.load(ServiceCapabilityFactory.createRequirement(Inspector.class, null, requirement), progressMonitor);
		for (CapabilityProvider provider: providers) {
			for (Object obj: provider.getPublisher().toIterable()) {
				@SuppressWarnings("unchecked")
				Inspector inspector = (Inspector) obj;
				ret = ret == null ? inspector : compose(ret, inspector);
			}
		}
		return ret == null ? nop() : ret;
	}

}