/*
* Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a
* cooperation between EGIZ, A-SIT Plus, A-SIT, and Graz University of Technology.
*
* Licensed under the EUPL, Version 1.2 or - as soon they will be approved by the European
* Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except in
* compliance with the Licence. You may obtain a copy of the Licence at:
* https://joinup.ec.europa.eu/news/understanding-eupl-v12
*
* Unless required by applicable law or agreed to in writing, software distributed under the Licence
* is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the Licence for the specific language governing permissions and limitations under
* the Licence.
*
* This product combines work with different licenses. See the "NOTICE" text file for details on the
* various modules and licenses. The "NOTICE" text file is part of the distribution. Any derivative
* works that you distribute must include a readable copy of the "NOTICE" text file.
*/
package at.gv.egiz.eaaf.core.impl.idp.process.springweb;
import java.io.Serializable;
import java.util.Map;
import java.util.Objects;
import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext;
import at.gv.egiz.eaaf.core.api.idp.process.ExpressionEvaluationContext;
import at.gv.egiz.eaaf.core.api.idp.process.ExpressionEvaluator;
import at.gv.egiz.eaaf.core.impl.idp.process.model.Transition;
import org.apache.commons.lang3.BooleanUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.expression.BeanFactoryResolver;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
/**
* Expression evaluator for processing {@link Transition} conditions allowing to.
*
* - reference Spring beans from the application context using {@code @myBeanName...},
* - {@link ExecutionContext} properties using {@code ctx['property']},
* - Multi valued {@link HttpServletRequest} parameters using {@code requestParameters['foo']}
* (keep in mind that this expression returns an array of String values) and
* - Single valued {@link HttpServletRequest} parameters using
* {@code requestParameter['foo']}
*
*
* @author tknall
*
*/
public class SpringWebExpressionEvaluator implements ExpressionEvaluator {
private final Logger log = LoggerFactory.getLogger(getClass());
private final ExpressionParser parser = new SpelExpressionParser();
private final StandardEvaluationContext evaluationContext = new StandardEvaluationContext();
@Autowired(required = false)
private ApplicationContext ctx;
@PostConstruct
private void init() {
if (ctx != null) {
evaluationContext.setBeanResolver(new BeanFactoryResolver(ctx));
}
}
/**
* Evaluation context that provides access to {@link HttpServletRequest} parameters using
* {@code requestParameter['foo']} for single value parameters or {@code requestParameters['foo']}
* for multi value parameters. Basic calls to {@code ctx} will be delegated.
*
* @author tknall
*
*/
private static class SpringWebExpressionEvaluationContext implements ExpressionEvaluationContext {
private static final long serialVersionUID = 1L;
/**
* Creates a new expression evaluation context, providing access to HttpServletRequest
* parameter(s).
*
* @param delegate The original {@link ExpressionEvaluationContext} to be delegated to for
* {@code ctx['foo']} expressions.
*/
public SpringWebExpressionEvaluationContext(final ExpressionEvaluationContext delegate) {
this.delegate = delegate;
}
private final ExpressionEvaluationContext delegate;
@Override
public Map getCtx() {
return delegate.getCtx();
}
}
@Override
public boolean evaluate(final ExpressionEvaluationContext expressionContext,
final String expression) {
Objects.requireNonNull(expression, "Expression must not be null.");
log.trace("Evaluating '{}'.", expression);
final Expression expr = parser.parseExpression(expression);
Boolean result = null;
try {
result = expr.getValue(evaluationContext,
new SpringWebExpressionEvaluationContext(expressionContext), Boolean.class);
if (result == null) {
log.debug("Evaluation of '{}' results in null-value.", expression);
} else {
log.debug("Expression '{}' -> {}", expression, result);
}
} catch (final Exception e) {
log.warn("Expression '{}' could not be processed.", expression, e);
}
return BooleanUtils.isTrue(result);
}
}