PageRenderTime 66ms CodeModel.GetById 36ms RepoModel.GetById 0ms app.codeStats 1ms

/src/main/java/org/apache/camel/language/simple/ast/BinaryExpression.java

https://github.com/davsclaus/camel-simple2
Java | 238 lines | 181 code | 30 blank | 27 comment | 59 complexity | 4dbcc64eaceb8ffbedb0be8a0c3702c4 MD5 | raw file
  1. /**
  2. * Licensed to the Apache Software Foundation (ASF) under one or more
  3. * contributor license agreements. See the NOTICE file distributed with
  4. * this work for additional information regarding copyright ownership.
  5. * The ASF licenses this file to You under the Apache License, Version 2.0
  6. * (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. package org.apache.camel.language.simple.ast;
  18. import java.util.ArrayList;
  19. import java.util.Iterator;
  20. import java.util.List;
  21. import java.util.regex.Matcher;
  22. import java.util.regex.Pattern;
  23. import org.apache.camel.Exchange;
  24. import org.apache.camel.Expression;
  25. import org.apache.camel.Predicate;
  26. import org.apache.camel.builder.ExpressionBuilder;
  27. import org.apache.camel.builder.PredicateBuilder;
  28. import org.apache.camel.builder.ValueBuilder;
  29. import org.apache.camel.language.simple.BinaryOperatorType;
  30. import org.apache.camel.language.simple.SimpleIllegalSyntaxException;
  31. import org.apache.camel.language.simple.SimpleParserException;
  32. import org.apache.camel.language.simple.SimpleToken;
  33. import org.apache.camel.util.ObjectHelper;
  34. /**
  35. * Represents a binary expression in the AST.
  36. */
  37. public class BinaryExpression extends BaseSimpleNode {
  38. // this is special for the range operator where you define the range as from..to (where from and to are numbers)
  39. private static final Pattern RANGE_PATTERN = Pattern.compile("^(\\d+)(\\.\\.)(\\d+)$");
  40. private final BinaryOperatorType operator;
  41. private SimpleNode left;
  42. private SimpleNode right;
  43. public BinaryExpression(SimpleToken token) {
  44. super(token);
  45. operator = BinaryOperatorType.asOperator(token.getText());
  46. }
  47. @Override
  48. public String toString() {
  49. return left + " " + token.getText() + " " + right;
  50. }
  51. public boolean acceptLeftNode(SimpleNode lef) {
  52. this.left = lef;
  53. return true;
  54. }
  55. public boolean acceptRightNode(SimpleNode right) {
  56. this.right = right;
  57. return true;
  58. }
  59. public BinaryOperatorType getOperator() {
  60. return operator;
  61. }
  62. @Override
  63. public Expression createExpression(String expression) {
  64. ObjectHelper.notNull(left, "left node", this);
  65. ObjectHelper.notNull(right, "right node", this);
  66. final Expression leftExp = left.createExpression(expression);
  67. final Expression rightExp = right.createExpression(expression);
  68. if (operator == BinaryOperatorType.EQ) {
  69. return createExpression(leftExp, rightExp, PredicateBuilder.isEqualTo(leftExp, rightExp));
  70. } else if (operator == BinaryOperatorType.GT) {
  71. return createExpression(leftExp, rightExp, PredicateBuilder.isGreaterThan(leftExp, rightExp));
  72. } else if (operator == BinaryOperatorType.GTE) {
  73. return createExpression(leftExp, rightExp, PredicateBuilder.isGreaterThanOrEqualTo(leftExp, rightExp));
  74. } else if (operator == BinaryOperatorType.LT) {
  75. return createExpression(leftExp, rightExp, PredicateBuilder.isLessThan(leftExp, rightExp));
  76. } else if (operator == BinaryOperatorType.LTE) {
  77. return createExpression(leftExp, rightExp, PredicateBuilder.isLessThanOrEqualTo(leftExp, rightExp));
  78. } else if (operator == BinaryOperatorType.NOT_EQ) {
  79. return createExpression(leftExp, rightExp, PredicateBuilder.isNotEqualTo(leftExp, rightExp));
  80. } else if (operator == BinaryOperatorType.CONTAINS) {
  81. return createExpression(leftExp, rightExp, PredicateBuilder.contains(leftExp, rightExp));
  82. } else if (operator == BinaryOperatorType.NOT_CONTAINS) {
  83. return createExpression(leftExp, rightExp, PredicateBuilder.not(PredicateBuilder.contains(leftExp, rightExp)));
  84. } else if (operator == BinaryOperatorType.IS || operator == BinaryOperatorType.NOT_IS) {
  85. return createIsExpression(expression, leftExp, rightExp);
  86. } else if (operator == BinaryOperatorType.REGEX || operator == BinaryOperatorType.NOT_REGEX) {
  87. return createRegexExpression(leftExp, rightExp);
  88. } else if (operator == BinaryOperatorType.IN || operator == BinaryOperatorType.NOT_IN) {
  89. return createInExpression(leftExp, rightExp);
  90. } else if (operator == BinaryOperatorType.RANGE || operator == BinaryOperatorType.NOT_RANGE) {
  91. return createRangeExpression(expression, leftExp, rightExp);
  92. }
  93. throw new SimpleParserException("Unknown binary operator " + operator, token.getIndex());
  94. }
  95. private Expression createIsExpression(final String expression, final Expression leftExp, final Expression rightExp) {
  96. return new Expression() {
  97. @Override
  98. public <T> T evaluate(Exchange exchange, Class<T> type) {
  99. Predicate predicate;
  100. String name = rightExp.evaluate(exchange, String.class);
  101. if (name == null || "null".equals(name)) {
  102. throw new SimpleIllegalSyntaxException(expression, right.getToken().getIndex(), operator + " operator cannot accept null. A class type must be provided.");
  103. }
  104. Class<?> rightType = exchange.getContext().getClassResolver().resolveClass(name);
  105. if (rightType == null) {
  106. throw new SimpleIllegalSyntaxException(expression, right.getToken().getIndex(), operator + " operator cannot find class with name: " + name);
  107. }
  108. predicate = PredicateBuilder.isInstanceOf(leftExp, rightType);
  109. if (operator == BinaryOperatorType.NOT_IS) {
  110. predicate = PredicateBuilder.not(predicate);
  111. }
  112. boolean answer = predicate.matches(exchange);
  113. return exchange.getContext().getTypeConverter().convertTo(type, answer);
  114. }
  115. @Override
  116. public String toString() {
  117. return left + " " + token.getText() + " " + right;
  118. }
  119. };
  120. }
  121. private Expression createRegexExpression(final Expression leftExp, final Expression rightExp) {
  122. return new Expression() {
  123. @Override
  124. public <T> T evaluate(Exchange exchange, Class<T> type) {
  125. // reg ex should use String pattern, so we evaluate the right hand side as a String
  126. Predicate predicate = PredicateBuilder.regex(leftExp, rightExp.evaluate(exchange, String.class));
  127. if (operator == BinaryOperatorType.NOT_REGEX) {
  128. predicate = PredicateBuilder.not(predicate);
  129. }
  130. boolean answer = predicate.matches(exchange);
  131. return exchange.getContext().getTypeConverter().convertTo(type, answer);
  132. }
  133. @Override
  134. public String toString() {
  135. return left + " " + token.getText() + " " + right;
  136. }
  137. };
  138. }
  139. private Expression createInExpression(final Expression leftExp, final Expression rightExp) {
  140. return new Expression() {
  141. @Override
  142. public <T> T evaluate(Exchange exchange, Class<T> type) {
  143. // okay the in operator is a bit more complex as we need to build a list of values
  144. // from the right hand side expression.
  145. // each element on the right hand side must be separated by comma (default for create iterator)
  146. Iterator<Object> it = ObjectHelper.createIterator(rightExp.evaluate(exchange, Object.class));
  147. List<Object> values = new ArrayList<Object>();
  148. while (it.hasNext()) {
  149. values.add(it.next());
  150. }
  151. // then reuse value builder to create the in predicate with the list of values
  152. ValueBuilder vb = new ValueBuilder(leftExp);
  153. Predicate predicate = vb.in(values.toArray());
  154. if (operator == BinaryOperatorType.NOT_IN) {
  155. predicate = PredicateBuilder.not(predicate);
  156. }
  157. boolean answer = predicate.matches(exchange);
  158. return exchange.getContext().getTypeConverter().convertTo(type, answer);
  159. }
  160. @Override
  161. public String toString() {
  162. return left + " " + token.getText() + " " + right;
  163. }
  164. };
  165. }
  166. private Expression createRangeExpression(final String expression, final Expression leftExp, final Expression rightExp) {
  167. return new Expression() {
  168. @Override
  169. public <T> T evaluate(Exchange exchange, Class<T> type) {
  170. Predicate predicate;
  171. String range = rightExp.evaluate(exchange, String.class);
  172. Matcher matcher = RANGE_PATTERN.matcher(range);
  173. if (matcher.matches()) {
  174. // wrap as constant expression for the from and to values
  175. Expression from = ExpressionBuilder.constantExpression(matcher.group(1));
  176. Expression to = ExpressionBuilder.constantExpression(matcher.group(3));
  177. // build a compound predicate for the range
  178. predicate = PredicateBuilder.isGreaterThanOrEqualTo(leftExp, from);
  179. predicate = PredicateBuilder.and(predicate, PredicateBuilder.isLessThanOrEqualTo(leftExp, to));
  180. } else {
  181. throw new SimpleIllegalSyntaxException(expression, right.getToken().getIndex(), operator + " operator is not valid. Valid syntax:'from..to' (where from and to are numbers).");
  182. }
  183. if (operator == BinaryOperatorType.NOT_RANGE) {
  184. predicate = PredicateBuilder.not(predicate);
  185. }
  186. boolean answer = predicate.matches(exchange);
  187. return exchange.getContext().getTypeConverter().convertTo(type, answer);
  188. }
  189. @Override
  190. public String toString() {
  191. return left + " " + token.getText() + " " + right;
  192. }
  193. };
  194. }
  195. private Expression createExpression(final Expression left, final Expression right, final Predicate predicate) {
  196. return new Expression() {
  197. @Override
  198. public <T> T evaluate(Exchange exchange, Class<T> type) {
  199. boolean answer = predicate.matches(exchange);
  200. return exchange.getContext().getTypeConverter().convertTo(type, answer);
  201. }
  202. @Override
  203. public String toString() {
  204. return left + " " + token.getText() + " " + right;
  205. }
  206. };
  207. }
  208. }