protected BigDecimal evaluate(com.udojava.evalex.Expression expression) {
    setExpressionCustomFunctions(expression);
    setExpressionCustomOperators(expression);
    setExpressionMathContext(expression);

    return expression.eval();
  }
  @Override
  @SuppressWarnings("unchecked")
  public T evaluate() throws DDMExpressionException {
    try {
      com.udojava.evalex.Expression expression =
          new com.udojava.evalex.Expression(_expressionString);

      for (Map.Entry<String, Variable> entry : _variables.entrySet()) {
        BigDecimal variableValue = getVariableValue(entry.getValue());

        expression.setVariable(entry.getKey(), variableValue);
      }

      BigDecimal result = evaluate(expression);

      return (T) toRetunType(result);
    } catch (Exception e) {
      throw new DDMExpressionException(e);
    }
  }
  protected com.udojava.evalex.Expression getExpression(String expressionString)
      throws DDMExpressionException {

    com.udojava.evalex.Expression expression = new com.udojava.evalex.Expression(expressionString);

    TokenExtractor tokenExtractor = new TokenExtractor(expressionString);

    Map<String, String> variableMap = tokenExtractor.getVariableMap();

    for (String key : variableMap.keySet()) {
      Variable variable = _variables.get(key);

      if (variable != null) {
        BigDecimal variableValue = getVariableValue(variable);

        expression.setVariable(key, variableValue);
      }
    }

    return expression;
  }
  protected void setExpressionMathContext(com.udojava.evalex.Expression expression) {

    expression.setPrecision(_mathContext.getPrecision());
    expression.setRoundingMode(_mathContext.getRoundingMode());
  }
  protected void setExpressionCustomOperators(com.udojava.evalex.Expression expression) {

    expression.addOperator(
        expression.new Operator("+", 20, true) {

          @Override
          public BigDecimal eval(BigDecimal parameter1, BigDecimal parameter2) {

            return new BigDecimal(parameter1.doubleValue() + parameter2.doubleValue());
          }
        });

    expression.addOperator(
        expression.new Operator("-", 20, true) {

          @Override
          public BigDecimal eval(BigDecimal parameter1, BigDecimal parameter2) {

            return new BigDecimal(parameter1.doubleValue() - parameter2.doubleValue());
          }
        });

    expression.addOperator(
        expression.new Operator("*", 30, true) {

          @Override
          public BigDecimal eval(BigDecimal parameter1, BigDecimal parameter2) {

            return new BigDecimal(parameter1.doubleValue() * parameter2.doubleValue());
          }
        });

    expression.addOperator(
        expression.new Operator("/", 30, true) {

          @Override
          public BigDecimal eval(BigDecimal parameter1, BigDecimal parameter2) {

            return new BigDecimal(parameter1.doubleValue() / parameter2.doubleValue());
          }
        });

    expression.addOperator(
        expression.new Operator("%", 30, true) {

          @Override
          public BigDecimal eval(BigDecimal parameter1, BigDecimal parameter2) {

            return new BigDecimal(parameter1.doubleValue() % parameter2.doubleValue());
          }
        });

    expression.addOperator(
        expression.new Operator("^", 40, false) {

          @Override
          public BigDecimal eval(BigDecimal parameter1, BigDecimal parameter2) {

            double pow = Math.pow(parameter1.doubleValue(), parameter2.doubleValue());

            return new BigDecimal(pow);
          }
        });
  }
  protected void setExpressionCustomFunctions(com.udojava.evalex.Expression expression) {

    expression.addFunction(
        expression.new Function("between", 3) {

          @Override
          public BigDecimal eval(List<BigDecimal> parameters) {
            BigDecimal parameter = parameters.get(0);

            BigDecimal minParameter = parameters.get(1);
            BigDecimal maxParameter = parameters.get(2);

            if ((parameter.compareTo(minParameter) >= 0)
                && (parameter.compareTo(maxParameter) <= 0)) {

              return BigDecimal.ONE;
            }

            return BigDecimal.ZERO;
          }
        });

    expression.addFunction(
        expression.new Function("concat", -1) {

          @Override
          public BigDecimal eval(List<BigDecimal> parameters) {
            StringBundler sb = new StringBundler(parameters.size());

            for (BigDecimal parameter : parameters) {
              if (isStringBlank(parameter)) {
                continue;
              }

              String string = decodeString(parameter);

              sb.append(string);
            }

            if (sb.index() == 0) {
              return BigDecimal.ZERO;
            }

            return encode(sb.toString());
          }
        });

    expression.addFunction(
        expression.new Function("contains", 2) {

          @Override
          public BigDecimal eval(List<BigDecimal> parameters) {
            BigDecimal parameter1 = parameters.get(0);
            BigDecimal parameter2 = parameters.get(1);

            if (isStringBlank(parameter1, parameter2)) {
              return BigDecimal.ONE;
            }

            String string1 = StringUtil.toLowerCase(decodeString(parameter1));
            String string2 = StringUtil.toLowerCase(decodeString(parameter2));

            if (string1.contains(string2)) {
              return BigDecimal.ONE;
            }

            return BigDecimal.ZERO;
          }
        });

    expression.addFunction(
        expression.new Function("equals", 2) {

          @Override
          public BigDecimal eval(List<BigDecimal> parameters) {
            BigDecimal parameter1 = parameters.get(0);
            BigDecimal parameter2 = parameters.get(1);

            if (isStringBlank(parameter1, parameter2)) {
              return BigDecimal.ONE;
            }

            String string1 = decodeString(parameter1);
            String string2 = decodeString(parameter2);

            if (string1.equals(string2)) {
              return BigDecimal.ONE;
            }

            return BigDecimal.ZERO;
          }
        });

    expression.addFunction(
        expression.new Function("isEmailAddress", 1) {

          @Override
          public BigDecimal eval(List<BigDecimal> parameters) {
            String string = decodeString(parameters.get(0));

            if (Validator.isEmailAddress(string)) {
              return BigDecimal.ONE;
            }

            return BigDecimal.ZERO;
          }
        });

    expression.addFunction(
        expression.new Function("isURL", 1) {

          @Override
          public BigDecimal eval(List<BigDecimal> parameters) {
            String string = decodeString(parameters.get(0));

            if (Validator.isUrl(string)) {
              return BigDecimal.ONE;
            }

            return BigDecimal.ZERO;
          }
        });

    expression.addFunction(
        expression.new Function("sum", -1) {

          @Override
          public BigDecimal eval(List<BigDecimal> parameters) {
            BigDecimal sum = new BigDecimal(0);

            for (BigDecimal parameter : parameters) {
              sum = sum.add(parameter);
            }

            return sum;
          }
        });
  }