/*******************************************************************************
* Copyright 2013-2016 alladin-IT GmbH
*
* 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 at.alladin.rmbt.qos;
import java.lang.reflect.Field;
import java.util.Collection;
import at.alladin.rmbt.qos.annotations.NonComparableField;
import at.alladin.rmbt.qos.testscript.TestScriptInterpreter;
import at.alladin.rmbt.qos.testscript.TestScriptInterpreter.EvalResult;
import at.alladin.rmbt.shared.hstoreparser.Hstore;
import at.alladin.rmbt.shared.hstoreparser.HstoreParser;
/**
*
* @author lb
*
*/
public class ResultComparer {
public final static int RESULT_COULD_NOT_COMPARE = -1;
public final static int RESULT_FAILURE = 0;
public final static int RESULT_SUCCESS = 1;
public final static int RESULT_INFO = 2;
/**
*
* @param result1
* @param result2
* @return
* @throws IllegalAccessException
* @throws IllegalArgumentException
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
public static <T extends AbstractResult> ResultDesc compare(AbstractResult result1, AbstractResult result2, Hstore hstore, ResultOptions options) throws IllegalArgumentException, IllegalAccessException {
HstoreParser<T> parser = (HstoreParser<T>) hstore.getParser(result1.getClass());
if (!result1.getClass().equals(result2.getClass())) {
System.out.println("could not compare: " + result1.getClass() + " <-> " + result2.getClass());
return null;
}
if ((result1.getOperator()!=null || result1.getEvaluate()!=null) && result2.getOperator()==null) {
for (Field f : parser.getAnnotatedFields()) {
f.setAccessible(true);
if (!f.isAnnotationPresent(NonComparableField.class) && f.get(result1) != null && !Collection.class.isAssignableFrom(f.getType())) {
Object r = TestScriptInterpreter.interprete(String.valueOf(f.get(result1)), hstore, result2, false, options);
f.set(result2, (r instanceof EvalResult) ? r : String.valueOf(r));
}
}
return getResultDescription(result1, result2, hstore, options);
}
else if ((result2.getOperator()!=null || result2.getEvaluate()!=null) && result1.getOperator()==null) {
for (Field f : parser.getAnnotatedFields()) {
f.setAccessible(true);
if (!f.isAnnotationPresent(NonComparableField.class) && f.get(result2) != null && !Collection.class.isAssignableFrom(f.getType())) {
Object r = TestScriptInterpreter.interprete(String.valueOf(f.get(result2)), hstore, result1, false, options);
f.set(result2, (r instanceof EvalResult) ? r : String.valueOf(r));
}
}
return getResultDescription(result2, result1, hstore, options);
}
System.out.println("Could not compare: Both comparators either set or not set or evaluate missing");
return null;
}
/**
*
* @param result1
* @param result2
* @param hstore
* @param options
* @return
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
private static ResultDesc getResultDescription(AbstractResult result1, AbstractResult result2, Hstore hstore, ResultOptions options) {
final int result = runCompare(result2, result1);
if ("true".equals(result1.getSuccessCondition()) || "1".equals(result1.getSuccessCondition())) {
if (result == RESULT_SUCCESS) {
return new ResultDesc(ResultDesc.STATUS_CODE_SUCCESS, result1.getOnSuccess(), result2, hstore, options);
}
else if (result == RESULT_FAILURE || result == RESULT_COULD_NOT_COMPARE) {
return new ResultDesc(ResultDesc.STATUS_CODE_FAILURE, result1.getOnFailure(), result2, hstore, options);
}
}
else {
if (result == RESULT_FAILURE) {
return new ResultDesc(ResultDesc.STATUS_CODE_SUCCESS, result1.getOnSuccess(), result2, hstore, options);
}
else if (result == RESULT_SUCCESS || result == RESULT_COULD_NOT_COMPARE) {
return new ResultDesc(ResultDesc.STATUS_CODE_FAILURE, result1.getOnFailure(), result2, hstore, options);
}
}
try {
return new ResultDesc(ResultDesc.StatusCode.values()[result], result1.getOnSuccess(), result2, hstore, options);
} catch (Exception e) {
//fallback: unknown status code:
return new ResultDesc(ResultDesc.StatusCode.INFO, result1.getOnSuccess(), result2, hstore, options);
}
}
/**
*
* @param result
* @param expectedResult
* @return
*/
private static int runCompare(AbstractResult<?> result, AbstractResult<?> expectedResult) {
//makes the comparison shorter (less code) and (maybe ;)) faster. needed for the logical xor operation:
if (expectedResult.getOperator()!=null) {
boolean controlFlag = (expectedResult.getOperator().equals(AbstractResult.COMPARATOR_EQUALS) ||
expectedResult.getOperator().equals(AbstractResult.COMPARATOR_GREATER_THEN) ||
expectedResult.getOperator().equals(AbstractResult.COMPARATOR_GREATER_OR_EQUALS)) ? true : false;
return runCompare(expectedResult.getOperator(), controlFlag, result, expectedResult);
}
else if (expectedResult.getEvaluate()!=null) {
//System.out.println(expectedResult.getClass() + " evaluate: " + expectedResult.getEvaluate());
final Object eval = expectedResult.getEvaluate();
if (eval instanceof String) {
return eval.equals("true") ? ResultComparer.RESULT_SUCCESS : ResultComparer.RESULT_FAILURE;
}
else if (eval instanceof EvalResult) {
switch (((EvalResult) eval).getType()) {
case FAILURE:
expectedResult.setOnFailure(((EvalResult) eval).getResultKey());
return RESULT_FAILURE;
case SUCCESS:
expectedResult.setOnSuccess(((EvalResult) eval).getResultKey());
return RESULT_SUCCESS;
default:
expectedResult.setOnSuccess(((EvalResult) eval).getResultKey());
return ((EvalResult) eval).getType().ordinal();
}
}
else {
return ResultComparer.RESULT_COULD_NOT_COMPARE;
}
}
return ResultComparer.RESULT_COULD_NOT_COMPARE;
}
/**
*
* @param operator
* @param controlFlag
* @param result
* @param expectedResult
* @return
*/
private static int runCompare(String operator, boolean controlFlag, Object result, Object expectedResult) {
try {
//try to compare each field if the expected result's field is not null
for (Field f: result.getClass().getDeclaredFields()) {
f.setAccessible(true);
if (f.get(expectedResult) != null) {
int compareResult = compareFields(f, operator, controlFlag, result, expectedResult);
if (compareResult != ResultComparer.RESULT_SUCCESS) {
return compareResult;
}
}
}
}
catch (Throwable t) {
t.printStackTrace();
return ResultComparer.RESULT_COULD_NOT_COMPARE;
}
return ResultComparer.RESULT_SUCCESS;
}
/**
*
* @param f
* @param controlFlag
* @param result
* @param expectedResult
* @return
*/
private static int compareFields(Field f, String operator, boolean controlFlag, Object result, Object expectedResult) {
//System.out.println("comparing: " + f.getName() + " operator: " + operator + " result: " + result + " expectedResult: " + expectedResult);
int resultOfCompare = ResultComparer.RESULT_SUCCESS;
try {
//make sure also private fields can be compared:
f.setAccessible(true);
//check if field is a collection... if true, then it will get a bit complicated here:
if (Collection.class.isAssignableFrom(f.getType())) {
int compareResult = ResultComparer.RESULT_SUCCESS;
//for each item on the right side (= expected test result) there must be (at least) one item on the left side (= test result),
//that fulfills the requirements of the equation to return TRUE
for (Object expectedItem : ((Collection<?>)f.get(expectedResult))) {
Collection<?> collection = (Collection<?>) f.get(result);
for (Object item : collection) {
//compare each field on the right side with the current field from the left side
if ((compareResult = runCompare(operator, controlFlag, item, expectedItem)) == ResultComparer.RESULT_SUCCESS) {
//if there was a success then return to previous for and continue with the next item
break;
}
}
}
return compareResult;
}
//if the field is not a collection it can (hopefully) be compared
else if (f.get(expectedResult) != null) {
final Object leftPart = String.valueOf(f.get(result));
final Object rightPart = String.valueOf(f.get(expectedResult));
//System.out.print(leftPart + " [" + operator + "] " + rightPart + " = ");
switch (operator) {
case AbstractResult.COMPARATOR_EQUALS:
case AbstractResult.COMPARATOR_NOT_EQUALS:
//System.out.println("-- EQ, NE --");
//use logical xor to determine the comparison result
if (String.valueOf(rightPart).trim().equals(String.valueOf(leftPart).trim()) ^ controlFlag) {
resultOfCompare = ResultComparer.RESULT_FAILURE;
}
break;
case AbstractResult.COMPARATOR_GREATER_THEN:
case AbstractResult.COMPARATOR_LOWER_THEN:
//System.out.println("-- GT, LT --");
if ((compare(leftPart, rightPart) > 0) ^ controlFlag) {
resultOfCompare = ResultComparer.RESULT_FAILURE;
}
break;
case AbstractResult.COMPARATOR_GREATER_OR_EQUALS:
case AbstractResult.COMPARATOR_LOWER_OR_EQUALS:
//System.out.println("-- GE, LE --");
if ((compare(leftPart, rightPart) >= 0) ^ controlFlag) {
resultOfCompare = ResultComparer.RESULT_FAILURE;
}
break;
}
}
}
catch (Throwable t) {
t.printStackTrace();
System.out.println("Field: " + f.toString() + ", " + t.getClass().getCanonicalName() + ": " + t.getLocalizedMessage());
return ResultComparer.RESULT_COULD_NOT_COMPARE;
}
//System.out.println(resultOfCompare);
return resultOfCompare;
}
/**
* Try to compare to objects. <br>
* First: check if objects are both not null. If not true the not null object is "greater".<br>
* If true: try a long comparison; on exception: try a double comparison and on another exception: finally try a string comparison
* @param o1
* @param o2
* @return
*/
public final static int compare(Object o1, Object o2) {
if (o1 != null && o2 != null) {
final String s1 = String.valueOf(o1);
final String s2 = String.valueOf(o2);
try {
final Long l1 = Long.valueOf(s1);
final Long l2 = Long.valueOf(s2);
return Long.compare(l1, l2);
}
catch (NumberFormatException e1) {
try {
final Double d1 = Double.valueOf(s1);
final Double d2 = Double.valueOf(s2);
return Double.compare(d1, d2);
}
catch (NumberFormatException e2) {
return s1.compareTo(s2);
}
}
}
else if (o2 == null) {
return 1;
}
else if (o1 == null) {
return -1;
}
return 0;
}
}