/*******************************************************************************
* (c) Copyright 2016 Hewlett-Packard Development Company, L.P.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Apache License v2.0 which accompany this distribution.
*
* The Apache License is available at
* http://www.apache.org/licenses/LICENSE-2.0
*
*******************************************************************************/
package io.cloudslang.lang.runtime.bindings;
import io.cloudslang.lang.entities.ScoreLangConstants;
import io.cloudslang.lang.entities.SystemProperty;
import io.cloudslang.lang.entities.bindings.Result;
import io.cloudslang.lang.entities.bindings.values.Value;
import io.cloudslang.lang.entities.utils.ExpressionUtils;
import io.cloudslang.lang.entities.utils.MapUtils;
import io.cloudslang.lang.entities.utils.ResultUtils;
import io.cloudslang.lang.runtime.bindings.scripts.ScriptEvaluator;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* User: stoneo
* Date: 06/11/2014
* Time: 09:32
*/
@Component
public class ResultsBinding {
@Autowired
public ScriptEvaluator scriptEvaluator;
/**
* Resolves the result name of an executable based on the list of all the possible results, the run context
* and in the case of a flow, also the already preset result name
* <p>
* Throws a runtime exception in the following cases:
* 1. No possible results were given
* 2. In the case of a flow, the preset result name is not present in the possible results list
* 3. One or more of the results contains an illegal expression - not evaluated to true\false value
* 4. No result was resolved - none of the results expression returned true
*
* @param inputs the executable's inputs
* @param context the run context
* @param possibleResults list of all the possible Result objects of the executable
* @param presetResult a given result name. Will be not null only in the case of resolving a result of a flow
* @return the resolved result name
*/
public String resolveResult(Map<String, Value> inputs,
Map<String, Value> context,
Set<SystemProperty> systemProperties,
List<Result> possibleResults,
String presetResult) {
// We must have possible results
if (CollectionUtils.isEmpty(possibleResults)) {
throw new RuntimeException("No results were found");
}
// In case of calculating the result of a flow, we already have a preset result from the last step of the flow,
// we look for it in the possible results of the flow.
// If the flow has it as a possible result, we return it as the resolved result.
// If not, we throw an exception
if (presetResult != null) {
for (Result possibleResult : possibleResults) {
if (presetResult.equals(possibleResult.getName())) {
return presetResult;
}
}
throw new RuntimeException("Result: " + presetResult +
" that was calculated in the last step is not a possible result of the flow.");
}
// In the case of operation, we resolve the result by searching for the first result with a true expression
// An empty expression passes as true
for (Result result : possibleResults) {
String resultName = result.getName();
if (ResultUtils.isDefaultResult(result)) {
return resultName;
}
Serializable rawValue = result.getValue().get();
if (rawValue instanceof String) {
String expression = ExpressionUtils.extractExpression(rawValue);
if (expression == null) {
throw new RuntimeException(
"Error resolving the result. The expression: '" + rawValue + "' is not valid." +
" Accepted format is: " + ScoreLangConstants.EXPRESSION_START_DELIMITER +
" expression " + ScoreLangConstants.EXPRESSION_END_DELIMITER);
}
Map<String, Value> scriptContext = MapUtils.mergeMaps(inputs, context);
try {
Value expressionResult = scriptEvaluator.evalExpr(expression, scriptContext, systemProperties,
result.getFunctionDependencies());
Boolean evaluatedResult;
if (expressionResult.get() instanceof Integer) {
evaluatedResult = (Integer) expressionResult.get() != 0;
} else {
evaluatedResult = (Boolean) expressionResult.get();
}
if (evaluatedResult == null) {
throw new RuntimeException("Expression of the operation result: " + expression +
" cannot be evaluated correctly to true or false value");
}
if (evaluatedResult) {
return resultName;
}
} catch (ClassCastException ex) {
throw new RuntimeException("Error resolving the result. The expression " + expression +
" does not return boolean value", ex);
} catch (Throwable t) {
throw new RuntimeException("Error evaluating result: '" + resultName + "',\n\tError is: " +
t.getMessage(), t);
}
} else {
throw new RuntimeException("Error resolving the result. Value: '" + rawValue + "' is not valid.");
}
}
throw new RuntimeException("No possible result was resolved");
}
}