/*******************************************************************************
* Copyright (c) 2013 Rene Schneider, GEBIT Solutions GmbH and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package de.gebit.integrity.operations.standard.operands;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import com.google.inject.Inject;
import de.gebit.integrity.operations.UnexecutableException;
import de.gebit.integrity.parameter.conversion.ValueConverter;
import de.gebit.integrity.utils.JavaTypeUtil;
/**
* Abstract base class for operator nodes. An operator node is a node in the AST built to evaluate
* {@link de.gebit.integrity.dsl.StandardOperation}s.
*
* @param <LEFT>
* the left argument
* @param <RIGHT>
* the right argument
* @author Rene Schneider - initial API and implementation
*
*/
public abstract class OperatorNode<LEFT extends Object, RIGHT extends Object> {
/**
* The left operand.
*/
private Object leftOperand;
/**
* The right operand.
*/
private Object rightOperand;
/**
* The value converter to use.
*/
@Inject
private ValueConverter valueConverter;
/**
* Creates an instance.
*
* @param aLeftOperand
* the left operand
* @param aRightOperand
* the right operand
*/
public OperatorNode(Object aLeftOperand, Object aRightOperand) {
leftOperand = aLeftOperand;
rightOperand = aRightOperand;
}
/**
* Returns the left operand in an evaluated version.
*
* @return the result of the evaluation
* @throws UnexecutableException
*/
protected Object getEvaluatedLeftOperand() throws UnexecutableException {
if (leftOperand instanceof OperatorNode<?, ?>) {
return ((OperatorNode<?, ?>) leftOperand).evaluate();
} else {
return leftOperand;
}
}
/**
* Returns the right operand in an evaluated version.
*
* @return the result of the evaluation
* @throws UnexecutableException
*/
protected Object getEvaluatedRightOperand() throws UnexecutableException {
if (rightOperand instanceof OperatorNode<?, ?>) {
return ((OperatorNode<?, ?>) rightOperand).evaluate();
} else {
return rightOperand;
}
}
/**
* Evaluates the whole node.
*
* @return the evaluation result
* @throws UnexecutableException
*/
@SuppressWarnings("unchecked")
public Object evaluate() throws UnexecutableException {
Type tempType = JavaTypeUtil.findGenericInterfaceOrSuperType(getClass(), OperatorNode.class);
if (tempType != null) {
Class<?> tempLeftOperandType = (Class<?>) ((ParameterizedType) tempType).getActualTypeArguments()[0];
Class<?> tempRightOperandType = (Class<?>) ((ParameterizedType) tempType).getActualTypeArguments()[1];
LEFT tempConvertedLeftOperand = (LEFT) valueConverter.convertValue(tempLeftOperandType,
getEvaluatedLeftOperand(), null);
RIGHT tempConvertedRightOperand = (RIGHT) valueConverter.convertValue(tempRightOperandType,
getEvaluatedRightOperand(), null);
return evaluateInternal(tempConvertedLeftOperand, tempConvertedRightOperand);
} else {
throw new IllegalArgumentException("Was unable to find valid generic Conversion superinterface");
}
}
/**
* Must be implemented by subclasses to implement the actual evaluation of this node. It will get evaluated and
* converted operands and needs to return the result of the evaluation.
*
* @param aLeftOperand
* the evaluated left operand
* @param aRightOperand
* the evaluated right operand
* @return the result of the evaluation
*/
protected abstract Object evaluateInternal(LEFT aLeftOperand, RIGHT aRightOperand) throws UnexecutableException;
}