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

net.sf.gluebooster.java.booster.basic.transformation.CallableByCalling Maven / Gradle / Ivy

package net.sf.gluebooster.java.booster.basic.transformation;

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import net.sf.gluebooster.java.booster.essentials.eventsCommands.Callable;
import net.sf.gluebooster.java.booster.essentials.eventsCommands.CallableAbstraction;
import net.sf.gluebooster.java.booster.essentials.eventsCommands.CallableByConstant;
import net.sf.gluebooster.java.booster.essentials.math.Condition;
import net.sf.gluebooster.java.booster.essentials.math.Anything;
import net.sf.gluebooster.java.booster.essentials.math.ConditionBoostUtils;
import net.sf.gluebooster.java.booster.essentials.meta.objects.ObjectDescription;
import net.sf.gluebooster.java.booster.essentials.utils.Constants;
import net.sf.gluebooster.java.booster.essentials.utils.ContainerBoostUtils;

/**
 * Executes multiple callables parallel and returns their results as array.
 * 
 * @defaultParamText indicesOfGaps The indices of the gaps in the defaultParmetersWithGaps
 * @defaultParamText name the name of the callable
 * @defaultParamText callablesOrConstants all objects that are not callables are interpreted as constants
 * 
 * @author cbauer
 *
 * @param 
 *            parameter of the calls
 * @param 
 *            result of the call
 */
public class CallableByCalling extends CallableAbstraction {

	/**
	 * An optional condition that decides whether the callables or elseCallables will be executed.
	 */
	private Callable ifCondition;
	/**
	 * The callables to be called (if the if condition is fulfilled (or not defined))
	 */
	private Callable[] callables;

	/**
	 * The callables to be called if the if-condition is not fulfilled
	 */
	private Callable[] elseCallables;

	/**
	 * Default parameters. May contain nulls (gaps) that will be filled in with the parameters of the call.
	 */
	private Parameter[] defaultParmetersWithGaps;

	/**
	 * The indices of the gaps in the defaultParmetersWithGaps.
	 */
	private int[] indicesOfTheGaps;
	/**
	 * Should the parameters of the call be appended to the result
	 */
	private boolean appendCallParameters = false;

	/**
	 * 
	 * @param callable
	 *            will be called
	 */
	public CallableByCalling(Object name, Callable callable, Parameter[] defaultParmetersWithGaps, int[] indicesOfGaps) {
		this(name, new Callable[] { callable }, defaultParmetersWithGaps, indicesOfGaps);
	}

	public CallableByCalling() {
	}

	public CallableByCalling(Object name) {
		this(name, null);
	}

	/**
	 * @param resultClass
	 *            class of the result of the call
	 */
	public CallableByCalling(Object name, Object[] callablesOrConstants, Class resultClass) {
		this(name, callablesOrConstants, null, null, resultClass);
	}

	public CallableByCalling(Object name, Object[] callablesOrConstants) {
		this(name, callablesOrConstants, null, null, null);
	}

	/**
	 * 
	 *           
	 */
	public CallableByCalling(Object name, Object[] callablesOrConstants, Parameter[] defaultParmetersWithGaps, int[] indicesOfGaps) {
		this(name, callablesOrConstants, defaultParmetersWithGaps, indicesOfGaps, null);

	}

	/**
	 * @param resultClass
	 *            class of the result of the call
	 */
	public CallableByCalling(Object name, Object[] callablesOrConstants, Parameter[] defaultParmetersWithGaps, int[] indicesOfGaps, Class resultClass) {
		super(name, null, resultClass);
		if (callablesOrConstants != null) {
			this.callables = new Callable[callablesOrConstants.length];
			for (int i = 0; i < callables.length; i++)
				if (callablesOrConstants[i] == null) {
					throw new IllegalStateException("callable must not be null " + i);
				} else if (callablesOrConstants[i] instanceof Callable) {
					callables[i] = (Callable) callablesOrConstants[i];
				} else {
					callables[i] = new CallableByConstant(callablesOrConstants[i]);
			}
		}

		this.defaultParmetersWithGaps = defaultParmetersWithGaps;

		if (indicesOfGaps != null) {
			indicesOfTheGaps = indicesOfGaps;
		} else {
			List indices = new ArrayList();
			if (defaultParmetersWithGaps != null) {
				for (int i = 0; i < defaultParmetersWithGaps.length; i++) {
					if (defaultParmetersWithGaps[i] == null) {
						indices.add(i);
					}
				}
			}

			indicesOfTheGaps = new int[indices.size()];
			for (int i = 0; i < indicesOfTheGaps.length; i++) {
				indicesOfTheGaps[i] = indices.get(i);
			}

		}

	}

	/**
	 * Creates a callable that represents an if...then construct.
	 * 
	 * @param ifCondition
	 *            the condition
	 * @param then
	 *            the operation if the condition is fulfilled
	 * @return the created callable
	 */
	public static CallableByCalling doIf(Object name, Callable ifCondition, Callable[] then) {
		CallableByCalling result = new CallableByCalling<>(name, then);
		result.setIfCondition(ifCondition);
		return result;
	}

	/**
	 * 
	 * Creates a callable that represents an if...then construct.
	 * 
	 * @param ifCondition
	 *            the condition
	 * @param then
	 *            the operation if the condition is fulfilled
	 * @param elseCallables
	 *            the operations if the condition is not fulfilled
	 * @return the created callable
	 */
	public static CallableByCalling doIf(Object name, Callable ifCondition, Callable[] then, Callable[] elseCallables) {
		CallableByCalling result = doIf(name, ifCondition, then);
		result.setElseCallables(elseCallables);
		return result;
	}
	
	/**
	 * @param callable
	 *            will be called
	 * @param defaultParmetersWithGaps
	 *            Nulls will be filled in
	 */
	public CallableByCalling(Object name, Callable callable, Parameter[] defaultParmetersWithGaps) {
		this(name, new Callable[] { callable }, defaultParmetersWithGaps, null);
		// this.callables = callable;
		// this.defaultParmetersWithGaps = defaultParmetersWithGaps;
		// List indices = new ArrayList();
		// for (int i = 0; i < defaultParmetersWithGaps.length; i++) {
		// if (defaultParmetersWithGaps[i] == null) {
		// indices.add(i);
		// }
		// }
		//
		// indicesOfTheGaps = new int[indices.size()];
		// for (int i = 0; i < indicesOfTheGaps.length; i++) {
		// indicesOfTheGaps[i] = indices.get(i);
		// }
	}

	@Override
	public Result callImpl(Parameter... parameters) throws Exception {

		Callable[] callables = this.callables;
		
		if (ifCondition != null) {
			Boolean result = ifCondition.call(parameters);
			if (!Boolean.TRUE.equals(result)) {
				if (elseCallables != null) {
					callables = elseCallables;
				} else {
					throw new IllegalStateException(
							"if condition not fulfilled (but no else defined): " + ifCondition + "\nParameters: " + Arrays.asList(parameters));
				}
			}
		}
		
		
		
		Callable[] theCallables;
		Parameter[] newParameters;


		if (callables == null) {
			if (parameters[0].getClass().isArray()) {
				theCallables = (Callable[]) parameters[0];
			} else {
				theCallables = new Callable[] { (Callable) parameters[0] };
			}
			parameters = Arrays.copyOfRange(parameters, 1, parameters.length);

		} else {
			theCallables = callables;
		}


		if (defaultParmetersWithGaps == null) {
			newParameters = parameters;
		} else {
			newParameters = Arrays.copyOf(defaultParmetersWithGaps, defaultParmetersWithGaps.length);
			for (int i = 0; i < indicesOfTheGaps.length; i++) {
				newParameters[indicesOfTheGaps[i]] = parameters[i];
			}
		}

		int size = theCallables.length;
		int resultSize = size;
		if (appendCallParameters) {
			resultSize += parameters.length;
		}
		Object[] result = new Object[resultSize];
		for (int i = 0; i < size; i++) {
			result[i] = theCallables[i].call(newParameters);
		}

		if (appendCallParameters) {
			System.arraycopy(parameters, 0, result, size, parameters.length);
		}

		if (result.length == 1) {
			return (Result) result[0];
		} else {
			return (Result) result;
		}
	}

	public Callable getIfCondition() {
		return ifCondition;
	}

	public void setIfCondition(Callable ifCondition) {
		this.ifCondition = ifCondition;
	}

	public Callable[] getElseCallables() {
		return elseCallables;
	}

	public void setElseCallables(Callable[] elseCallables) {
		this.elseCallables = elseCallables;
	}

	public boolean isAppendCallParameters() {
		return appendCallParameters;
	}

	public void setAppendCallParameters(boolean appendCallParameters) {
		this.appendCallParameters = appendCallParameters;
	}

	@Override
	protected Condition computePostcondition(Condition optionalPrecondition) throws Exception {

		Object resultDescription = getResultDescription();
		if (resultDescription != null && (resultDescription instanceof Condition)) {
			return (Condition) resultDescription;
			// because it is probably better than the computed condition below.
		}

		int resultSize = 0;
		Callable[] usedCallables = null;
		if (callables != null) {
			resultSize = Math.max(resultSize, callables.length);
			usedCallables = callables;
		}
		if (elseCallables != null) {
			resultSize = Math.max(resultSize, elseCallables.length);
			usedCallables = elseCallables;// it is either these of the callables.
			// It is not (yet) possible to decide which are actually used.
		}

		if (optionalPrecondition != null) {
			if (appendCallParameters) {
				if (optionalPrecondition instanceof ObjectDescription)
					;
				Object value = ((ObjectDescription) optionalPrecondition).getValue();
				if (value != null && value.getClass().isArray()) {
					resultSize += Array.getLength(value);
				}
			}
		}

		ObjectDescription result = new ObjectDescription();
		result.setSubdescriptionType(Constants.ARRAY);
		result.setMinSize(resultSize);
		if (usedCallables != null) {
			for (Callable callable : usedCallables) {
				Condition cond = callable.getPostcondition(optionalPrecondition);
				if (cond instanceof ObjectDescription) {
					result.addSubdescription((ObjectDescription) cond);
				} else {
					result.addSubdescription(null);
				}
				// TODO improve the Objectdescription to be able to accept condtions as subdescriptions
			}
		}
		return result;
	}

	@Override
	public Condition getPrecondition() throws Exception {
		Condition result = null;
		if (ifCondition != null) {
			result = ifCondition.getPrecondition();
		} else if (callables != null) {
			for (Callable callable : callables) {
				if (result == null) {
					result = callable.getPrecondition();
				} else {
					getLog().warn("AND condition not yet implemented");
				}
			}
		} else {
			result = super.getPrecondition();
		}

		return result;
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy