001 /** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package org.apache.camel.language.simple; 018 019 import java.util.ArrayList; 020 import java.util.Iterator; 021 import java.util.List; 022 import java.util.regex.Matcher; 023 import java.util.regex.Pattern; 024 025 import org.apache.camel.Exchange; 026 import org.apache.camel.Expression; 027 import org.apache.camel.IsSingleton; 028 import org.apache.camel.Predicate; 029 import org.apache.camel.builder.ExpressionBuilder; 030 import org.apache.camel.builder.PredicateBuilder; 031 import org.apache.camel.builder.ValueBuilder; 032 import org.apache.camel.spi.Language; 033 import org.apache.camel.util.ObjectHelper; 034 import org.apache.commons.logging.Log; 035 import org.apache.commons.logging.LogFactory; 036 import static org.apache.camel.language.simple.SimpleLangaugeOperator.*; 037 038 /** 039 * Abstract base class for Simple languages. 040 */ 041 public abstract class SimpleLanguageSupport implements Language, IsSingleton { 042 043 protected static final Pattern PATTERN = Pattern.compile( 044 "^\\$\\{(.+)\\}\\s+(==|>|>=|<|<=|!=|contains|not contains|regex|not regex|in|not in)\\s+(.+)$"); 045 protected final Log log = LogFactory.getLog(getClass()); 046 047 public Predicate createPredicate(String expression) { 048 return PredicateBuilder.toPredicate(createExpression(expression)); 049 } 050 051 public Expression createExpression(String expression) { 052 Matcher matcher = PATTERN.matcher(expression); 053 if (matcher.matches()) { 054 if (log.isDebugEnabled()) { 055 log.debug("Expression is evaluated as operator expression: " + expression); 056 } 057 return createOperatorExpression(matcher, expression); 058 } else if (expression.indexOf("${") >= 0) { 059 if (log.isDebugEnabled()) { 060 log.debug("Expression is evaluated as complex expression: " + expression); 061 } 062 return createComplexConcatExpression(expression); 063 } else { 064 if (log.isDebugEnabled()) { 065 log.debug("Expression is evaluated as simple expression: " + expression); 066 } 067 return createSimpleExpression(expression); 068 } 069 } 070 071 private Expression createOperatorExpression(final Matcher matcher, final String expression) { 072 final Expression left = createSimpleExpression(matcher.group(1)); 073 final SimpleLangaugeOperator operator = asOperator(matcher.group(2)); 074 075 // the right hand side expression can either be a constant expression wiht ' ' 076 // or another simple expression using ${ } placeholders 077 String text = matcher.group(3); 078 079 final Expression right; 080 final Expression rightConverted; 081 // special null handling 082 if ("null".equals(text)) { 083 right = createConstantExpression(null); 084 rightConverted = right; 085 } else { 086 // text can either be a constant enclosed by ' ' or another expression using ${ } placeholders 087 String constant = ObjectHelper.between(text, "'", "'"); 088 if (constant == null) { 089 // if no ' ' around then fallback to the text itself 090 constant = text; 091 } 092 String simple = ObjectHelper.between(text, "${", "}"); 093 094 right = simple != null ? createSimpleExpression(simple) : createConstantExpression(constant); 095 // to support numeric comparions using > and < operators we must convert the right hand side 096 // to the same type as the left 097 rightConverted = ExpressionBuilder.convertToExpression(right, left); 098 } 099 100 return new Expression() { 101 public Object evaluate(final Exchange exchange) { 102 Predicate predicate = null; 103 if (operator == EQ) { 104 predicate = PredicateBuilder.isEqualTo(left, rightConverted); 105 } else if (operator == GT) { 106 predicate = PredicateBuilder.isGreaterThan(left, rightConverted); 107 } else if (operator == GTE) { 108 predicate = PredicateBuilder.isGreaterThanOrEqualTo(left, rightConverted); 109 } else if (operator == LT) { 110 predicate = PredicateBuilder.isLessThan(left, rightConverted); 111 } else if (operator == LTE) { 112 predicate = PredicateBuilder.isLessThanOrEqualTo(left, rightConverted); 113 } else if (operator == NOT) { 114 predicate = PredicateBuilder.isNotEqualTo(left, rightConverted); 115 } else if (operator == CONTAINS || operator == NOT_CONTAINS) { 116 predicate = PredicateBuilder.contains(left, rightConverted); 117 if (operator == NOT_CONTAINS) { 118 predicate = PredicateBuilder.not(predicate); 119 } 120 } else if (operator == REGEX || operator == NOT_REGEX) { 121 // reg ex should use String pattern, so we evalute the right hand side as a String 122 predicate = PredicateBuilder.regex(left, right.evaluate(exchange, String.class)); 123 if (operator == NOT_REGEX) { 124 predicate = PredicateBuilder.not(predicate); 125 } 126 } else if (operator == IN || operator == NOT_IN) { 127 // okay the in operator is a bit more complex as we need to build a list of values 128 // from the right handside expression. 129 // each element on the right handside must be separated by comma (default for create iterator) 130 Iterator it = ObjectHelper.createIterator(right.evaluate(exchange)); 131 List<Object> values = new ArrayList<Object>(); 132 while (it.hasNext()) { 133 values.add(it.next()); 134 } 135 // then reuse value builder to create the in predicate with the list of values 136 ValueBuilder vb = new ValueBuilder(left); 137 predicate = vb.in(values.toArray()); 138 if (operator == NOT_IN) { 139 predicate = PredicateBuilder.not(predicate); 140 } 141 } 142 143 if (predicate == null) { 144 throw new IllegalArgumentException("Unsupported operator: " + operator + " for expression: " + expression); 145 } 146 return predicate.matches(exchange); 147 } 148 149 public <T> T evaluate(Exchange exchange, Class<T> type) { 150 Object result = evaluate(exchange); 151 return exchange.getContext().getTypeConverter().convertTo(type, result); 152 } 153 154 @Override 155 public String toString() { 156 return left + " " + operator + " " + right; 157 } 158 }; 159 } 160 161 protected Expression createComplexConcatExpression(String expression) { 162 List<Expression> results = new ArrayList<Expression>(); 163 164 int pivot = 0; 165 int size = expression.length(); 166 while (pivot < size) { 167 int idx = expression.indexOf("${", pivot); 168 if (idx < 0) { 169 results.add(createConstantExpression(expression, pivot, size)); 170 break; 171 } else { 172 if (pivot < idx) { 173 results.add(createConstantExpression(expression, pivot, idx)); 174 } 175 pivot = idx + 2; 176 int endIdx = expression.indexOf("}", pivot); 177 if (endIdx < 0) { 178 throw new IllegalArgumentException("Expecting } but found end of string for simple expression: " + expression); 179 } 180 String simpleText = expression.substring(pivot, endIdx); 181 182 Expression simpleExpression = createSimpleExpression(simpleText); 183 results.add(simpleExpression); 184 pivot = endIdx + 1; 185 } 186 } 187 return ExpressionBuilder.concatExpression(results, expression); 188 } 189 190 protected Expression createConstantExpression(String expression, int start, int end) { 191 return ExpressionBuilder.constantExpression(expression.substring(start, end)); 192 } 193 194 protected Expression createConstantExpression(String expression) { 195 return ExpressionBuilder.constantExpression(expression); 196 } 197 198 /** 199 * Creates the simple expression based on the extracted content from the ${ } place holders 200 * 201 * @param expression the content between ${ and } 202 * @return the expression 203 */ 204 protected abstract Expression createSimpleExpression(String expression); 205 206 protected String ifStartsWithReturnRemainder(String prefix, String text) { 207 if (text.startsWith(prefix)) { 208 String remainder = text.substring(prefix.length()); 209 if (remainder.length() > 0) { 210 return remainder; 211 } 212 } 213 return null; 214 } 215 }