ExpressionResolver.java

  1. package org.jbehave.core.expressions;

  2. import java.util.Arrays;
  3. import java.util.Iterator;
  4. import java.util.List;
  5. import java.util.Optional;
  6. import java.util.Set;
  7. import java.util.regex.Matcher;
  8. import java.util.regex.Pattern;

  9. public class ExpressionResolver {

  10.     private static final Pattern GREEDY_EXPRESSION_PATTERN = Pattern.compile("#\\{((?:(?!#\\{|\\$\\{).)*)}",
  11.             Pattern.DOTALL);
  12.     private static final Pattern RELUCTANT_EXPRESSION_PATTERN = Pattern.compile(
  13.             "#\\{((?:(?![#{])[^)](?![()]))*?|(?:(?!#\\{|\\$\\{).)*?\\)|(?:(?!#\\{|\\$\\{).)*?)}",
  14.             Pattern.DOTALL);
  15.     private static final List<Pattern> PATTERNS = Arrays.asList(RELUCTANT_EXPRESSION_PATTERN,
  16.             GREEDY_EXPRESSION_PATTERN);

  17.     private static final String REPLACEMENT_PATTERN = "\\#\\{%s\\}";

  18.     private final Set<ExpressionProcessor<?>> expressionProcessors;
  19.     private final ExpressionResolverMonitor expressionResolverMonitor;

  20.     public ExpressionResolver(Set<ExpressionProcessor<?>> expressionProcessors,
  21.             ExpressionResolverMonitor expressionResolverMonitor) {
  22.         this.expressionProcessors = expressionProcessors;
  23.         this.expressionResolverMonitor = expressionResolverMonitor;
  24.     }

  25.     /**
  26.      * Evaluates expressions including nested ones.
  27.      * <br>
  28.      * Syntax:
  29.      * <br>
  30.      * <code>
  31.      * #{expression(arguments...)}
  32.      * #{expression(arguments..., #{expression(arguments...)})}
  33.      * #{expression(arguments..., #{expression})}
  34.      * </code>
  35.      * <br>
  36.      * Example:
  37.      * <br>
  38.      * <code>
  39.      * #{shiftDate("1942-12-02T01:23:40+04:00", "yyyy-MM-dd'T'HH:mm:ssz", "P43Y4M3W3D")}
  40.      * <br>
  41.      * #{encodeToBase64(#{fromEpochSecond(-523641111)})}
  42.      * </code>
  43.      *
  44.      * @param stringWithExpressions the string with expressions to evaluate
  45.      * @return the resulting string with expression placeholders replaced with expressions evaluation results
  46.      */
  47.     public Object resolveExpressions(boolean dryRun, String stringWithExpressions) {
  48.         if (dryRun) {
  49.             return stringWithExpressions;
  50.         }
  51.         try {
  52.             return resolveExpressions(stringWithExpressions, PATTERNS.iterator());
  53.         } catch (RuntimeException e) {
  54.             expressionResolverMonitor.onExpressionProcessingError(stringWithExpressions, e);
  55.             throw e;
  56.         }
  57.     }

  58.     private Object resolveExpressions(String value, Iterator<Pattern> expressionPatterns) {
  59.         String processedValue = value;
  60.         Matcher expressionMatcher = expressionPatterns.next().matcher(processedValue);
  61.         boolean expressionFound = false;
  62.         while (expressionMatcher.find()) {
  63.             expressionFound = true;
  64.             String expression = expressionMatcher.group(1);
  65.             Object expressionResult = apply(expression);
  66.             if (!(expressionResult instanceof String) && ("#{" + expression + "}").equals(processedValue)) {
  67.                 return expressionResult;
  68.             }
  69.             if (!expressionResult.equals(expression)) {
  70.                 String regex = String.format(REPLACEMENT_PATTERN, Pattern.quote(expression));
  71.                 processedValue = processedValue.replaceFirst(regex,
  72.                         Matcher.quoteReplacement(String.valueOf(expressionResult)));
  73.                 expressionFound = false;
  74.                 expressionMatcher.reset(processedValue);
  75.             }
  76.         }
  77.         if (expressionFound && expressionPatterns.hasNext()) {
  78.             return resolveExpressions(processedValue, expressionPatterns);
  79.         }
  80.         return processedValue;
  81.     }

  82.     private Object apply(String expression) {
  83.         for (ExpressionProcessor<?> processor : expressionProcessors) {
  84.             Optional<?> optional = processor.execute(expression);
  85.             if (optional.isPresent()) {
  86.                 return optional.get();
  87.             }
  88.         }
  89.         return expression;
  90.     }
  91. }