/*******************************************************************************
* (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.LoopStatement;
import io.cloudslang.lang.entities.SystemProperty;
import io.cloudslang.lang.entities.bindings.values.Value;
import io.cloudslang.lang.entities.bindings.values.ValueFactory;
import io.cloudslang.lang.runtime.bindings.scripts.ScriptEvaluator;
import io.cloudslang.lang.runtime.env.Context;
import io.cloudslang.lang.runtime.env.ForLoopCondition;
import io.cloudslang.lang.runtime.env.LoopCondition;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang3.Validate;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import static io.cloudslang.lang.runtime.env.LoopCondition.LOOP_CONDITION_KEY;
@Component
public class LoopsBinding extends AbstractBinding {
public static final String FOR_LOOP_EXPRESSION_ERROR_MESSAGE = "Error evaluating for loop expression in step";
public static final String INVALID_MAP_EXPRESSION_MESSAGE = "Invalid expression for iterating maps";
private final Logger logger = Logger.getLogger(getClass());
@Autowired
private ScriptEvaluator scriptEvaluator;
public LoopCondition getOrCreateLoopCondition(
LoopStatement forLoopStatement,
Context flowContext,
Set<SystemProperty> systemProperties,
String nodeName) {
Validate.notNull(forLoopStatement, "loop statement cannot be null");
Validate.notNull(flowContext, "flow context cannot be null");
Validate.notNull(systemProperties, "system properties cannot be null");
Validate.notNull(nodeName, "node name cannot be null");
Value loopConditionValue = flowContext.getLanguageVariable(LOOP_CONDITION_KEY);
if (loopConditionValue == null) {
LoopCondition loopCondition =
createForLoopCondition(forLoopStatement, flowContext, systemProperties, nodeName);
flowContext.putLanguageVariable(LOOP_CONDITION_KEY, ValueFactory.create(loopCondition));
}
return (LoopCondition) flowContext.getLanguageVariable(LOOP_CONDITION_KEY).get();
}
public void incrementListForLoop(String varName, Context flowContext, ForLoopCondition forLoopCondition) {
Validate.notNull(varName, "loop var name cannot be null");
Validate.notNull(flowContext, "flow context cannot be null");
Validate.notNull(forLoopCondition, "for condition cannot be null");
Value varValue = forLoopCondition.next();
flowContext.putVariable(varName, varValue);
logger.debug("name: " + varName + ", value: " + varValue);
}
public void incrementMapForLoop(String keyName, String valueName, Context flowContext,
ForLoopCondition forLoopCondition) {
Validate.notNull(keyName, "loop key name cannot be null");
Validate.notNull(keyName, "loop value name cannot be null");
Validate.notNull(flowContext, "flow context cannot be null");
Validate.notNull(forLoopCondition, "for condition cannot be null");
@SuppressWarnings("unchecked") Map.Entry<Value, Value> entry =
(Map.Entry<Value, Value>) forLoopCondition.next().get();
Value keyFromIteration = entry.getKey();
Value valueFromIteration = entry.getValue();
flowContext.putVariable(keyName, keyFromIteration);
flowContext.putVariable(valueName, valueFromIteration);
logger.debug("key name: " + keyName + ", value: " + keyFromIteration);
logger.debug("value name: " + valueName + ", value: " + valueFromIteration);
}
private LoopCondition createForLoopCondition(
LoopStatement forLoopStatement,
Context flowContext,
Set<SystemProperty> systemProperties,
String nodeName) {
Map<String, Value> variables = flowContext.getImmutableViewOfVariables();
Value evalResult;
String collectionExpression = forLoopStatement.getExpression();
try {
evalResult = scriptEvaluator.evalExpr(collectionExpression, variables, systemProperties,
forLoopStatement.getFunctionDependencies());
} catch (Throwable t) {
throw new RuntimeException(FOR_LOOP_EXPRESSION_ERROR_MESSAGE + " '" +
nodeName + "',\n\tError is: " + t.getMessage(), t);
}
evalResult = getEvalResultForMap(evalResult, forLoopStatement, collectionExpression);
ForLoopCondition forLoopCondition = createForLoopCondition(evalResult);
if (forLoopCondition == null) {
throw new RuntimeException("collection expression: '" + collectionExpression +
"' in the 'for' loop " +
"in step: '" + nodeName + "' " +
"doesn't return an iterable, other types are not supported");
}
if (!forLoopCondition.hasMore()) {
throw new RuntimeException(FOR_LOOP_EXPRESSION_ERROR_MESSAGE + " '" + nodeName +
"',\n\tError is: expression is empty");
}
return forLoopCondition;
}
private ForLoopCondition createForLoopCondition(Value evalResult) {
Iterable<Value> iterable = getIterableFromEvalResult(evalResult);
if (iterable == null) {
return null;
}
return new ForLoopCondition(iterable);
}
}