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 */ 017package org.apache.camel.builder; 018 019import java.util.ArrayList; 020import java.util.Comparator; 021import java.util.List; 022import java.util.concurrent.atomic.AtomicReference; 023 024import org.apache.camel.Exchange; 025import org.apache.camel.Expression; 026import org.apache.camel.Predicate; 027import org.apache.camel.builder.xml.Namespaces; 028import org.apache.camel.spi.NamespaceAware; 029import org.apache.camel.support.ExpressionAdapter; 030import org.apache.camel.util.ExpressionToPredicateAdapter; 031 032/** 033 * A builder of expressions or predicates based on values. 034 * 035 * @version 036 */ 037public class ValueBuilder implements Expression, Predicate { 038 private Expression expression; 039 private boolean not; 040 041 public ValueBuilder(Expression expression) { 042 this.expression = expression; 043 } 044 045 @Override 046 public <T> T evaluate(Exchange exchange, Class<T> type) { 047 return expression.evaluate(exchange, type); 048 } 049 050 @Override 051 public boolean matches(Exchange exchange) { 052 return PredicateBuilder.toPredicate(getExpression()).matches(exchange); 053 } 054 055 public Expression getExpression() { 056 return expression; 057 } 058 059 @Override 060 public String toString() { 061 return expression.toString(); 062 } 063 064 // Predicate builders 065 // ------------------------------------------------------------------------- 066 067 public Predicate matches(Expression expression) { 068 return onNewPredicate(ExpressionToPredicateAdapter.toPredicate(expression)); 069 } 070 071 public ExpressionClause<Predicate> matches() { 072 // chicken-and-egg situation as we need to return an ExpressionClause 073 // which needs a right-hand side that is being built via the fluent 074 // builder that is returned, and therefore we need to use a ref 075 // to the expression (right hand side) that will be used below 076 // in the onNewPredicate where the actual matching is executed 077 final AtomicReference<Expression> ref = new AtomicReference<>(); 078 079 final ExpressionClause<Predicate> answer = new ExpressionClause<>( 080 onNewPredicate(new Predicate() { 081 @Override 082 public boolean matches(Exchange exchange) { 083 Expression left = expression; 084 Expression right = ref.get(); 085 return PredicateBuilder.isEqualTo(left, right).matches(exchange); 086 } 087 088 @Override 089 public String toString() { 090 return expression + " == " + ref.get(); 091 } 092 })); 093 094 final Expression right = new ExpressionAdapter() { 095 @Override 096 public Object evaluate(Exchange exchange) { 097 if (answer.getExpressionValue() != null) { 098 return answer.getExpressionValue().evaluate(exchange, Object.class); 099 } else { 100 return answer.getExpressionType().evaluate(exchange); 101 } 102 } 103 }; 104 // okay now we can set the reference to the right-hand-side 105 ref.set(right); 106 107 return answer; 108 } 109 110 public Predicate isNotEqualTo(Object value) { 111 Expression right = asExpression(value); 112 return onNewPredicate(PredicateBuilder.isNotEqualTo(expression, right)); 113 } 114 115 public Predicate isEqualTo(Object value) { 116 Expression right = asExpression(value); 117 return onNewPredicate(PredicateBuilder.isEqualTo(expression, right)); 118 } 119 120 public Predicate isEqualToIgnoreCase(Object value) { 121 Expression right = asExpression(value); 122 return onNewPredicate(PredicateBuilder.isEqualToIgnoreCase(expression, right)); 123 } 124 125 public Predicate isLessThan(Object value) { 126 Expression right = asExpression(value); 127 return onNewPredicate(PredicateBuilder.isLessThan(expression, right)); 128 } 129 130 public Predicate isLessThanOrEqualTo(Object value) { 131 Expression right = asExpression(value); 132 return onNewPredicate(PredicateBuilder.isLessThanOrEqualTo(expression, right)); 133 } 134 135 public Predicate isGreaterThan(Object value) { 136 Expression right = asExpression(value); 137 return onNewPredicate(PredicateBuilder.isGreaterThan(expression, right)); 138 } 139 140 public Predicate isGreaterThanOrEqualTo(Object value) { 141 Expression right = asExpression(value); 142 return onNewPredicate(PredicateBuilder.isGreaterThanOrEqualTo(expression, right)); 143 } 144 145 public Predicate isInstanceOf(Class<?> type) { 146 return onNewPredicate(PredicateBuilder.isInstanceOf(expression, type)); 147 } 148 149 public Predicate isNull() { 150 return onNewPredicate(PredicateBuilder.isNull(expression)); 151 } 152 153 public Predicate isNotNull() { 154 return onNewPredicate(PredicateBuilder.isNotNull(expression)); 155 } 156 157 public Predicate not(Predicate predicate) { 158 return onNewPredicate(PredicateBuilder.not(predicate)); 159 } 160 161 public Predicate in(Object... values) { 162 List<Predicate> predicates = new ArrayList<Predicate>(); 163 for (Object value : values) { 164 Expression right = asExpression(value); 165 right = ExpressionBuilder.convertToExpression(right, expression); 166 Predicate predicate = onNewPredicate(PredicateBuilder.isEqualTo(expression, right)); 167 predicates.add(predicate); 168 } 169 return in(predicates.toArray(new Predicate[predicates.size()])); 170 } 171 172 public Predicate in(Predicate... predicates) { 173 return onNewPredicate(PredicateBuilder.in(predicates)); 174 } 175 176 public Predicate startsWith(Object value) { 177 Expression right = asExpression(value); 178 return onNewPredicate(PredicateBuilder.startsWith(expression, right)); 179 } 180 181 public Predicate endsWith(Object value) { 182 Expression right = asExpression(value); 183 return onNewPredicate(PredicateBuilder.endsWith(expression, right)); 184 } 185 186 /** 187 * Create a predicate that the left hand expression contains the value of 188 * the right hand expression 189 * 190 * @param value the element which is compared to be contained within this 191 * expression 192 * @return a predicate which evaluates to true if the given value expression 193 * is contained within this expression value 194 */ 195 public Predicate contains(Object value) { 196 Expression right = asExpression(value); 197 return onNewPredicate(PredicateBuilder.contains(expression, right)); 198 } 199 200 /** 201 * Creates a predicate which is true if this expression matches the given 202 * regular expression 203 * 204 * @param regex the regular expression to match 205 * @return a predicate which evaluates to true if the expression matches the 206 * regex 207 */ 208 public Predicate regex(String regex) { 209 return onNewPredicate(PredicateBuilder.regex(expression, regex)); 210 } 211 212 // Expression builders 213 // ------------------------------------------------------------------------- 214 215 public ValueBuilder tokenize() { 216 return tokenize("\n"); 217 } 218 219 public ValueBuilder tokenize(String token) { 220 Expression newExp = ExpressionBuilder.tokenizeExpression(expression, token); 221 return onNewValueBuilder(newExp); 222 } 223 224 public ValueBuilder tokenize(String token, int group, boolean skipFirst) { 225 return tokenize(token, "" + group, skipFirst); 226 } 227 228 public ValueBuilder tokenize(String token, String group, boolean skipFirst) { 229 Expression newExp = ExpressionBuilder.tokenizeExpression(expression, token); 230 if (group == null && skipFirst) { 231 // wrap in skip first (if group then it has its own skip first logic) 232 newExp = ExpressionBuilder.skipFirstExpression(newExp); 233 } 234 newExp = ExpressionBuilder.groupIteratorExpression(newExp, token, group, skipFirst); 235 return onNewValueBuilder(newExp); 236 } 237 238 public ValueBuilder tokenizeXML(String tagName, String inheritNamespaceTagName) { 239 Expression newExp = ExpressionBuilder.tokenizeXMLExpression(tagName, inheritNamespaceTagName); 240 return onNewValueBuilder(newExp); 241 } 242 243 public ValueBuilder xtokenize(String path, Namespaces namespaces) { 244 return xtokenize(path, 'i', namespaces); 245 } 246 247 public ValueBuilder xtokenize(String path, char mode, Namespaces namespaces) { 248 Expression newExp = ExpressionBuilder.tokenizeXMLAwareExpression(path, mode); 249 ((NamespaceAware)newExp).setNamespaces(namespaces.getNamespaces()); 250 return onNewValueBuilder(newExp); 251 } 252 253 public ValueBuilder tokenizePair(String startToken, String endToken, boolean includeTokens) { 254 Expression newExp = ExpressionBuilder.tokenizePairExpression(startToken, endToken, includeTokens); 255 return onNewValueBuilder(newExp); 256 } 257 258 /** 259 * Tokenizes the string conversion of this expression using the given 260 * regular expression 261 */ 262 public ValueBuilder regexTokenize(String regex) { 263 Expression newExp = ExpressionBuilder.regexTokenizeExpression(expression, regex); 264 return onNewValueBuilder(newExp); 265 } 266 267 /** 268 * Replaces all occurrences of the regular expression with the given 269 * replacement 270 */ 271 public ValueBuilder regexReplaceAll(String regex, String replacement) { 272 Expression newExp = ExpressionBuilder.regexReplaceAll(expression, regex, replacement); 273 return onNewValueBuilder(newExp); 274 } 275 276 /** 277 * Replaces all occurrences of the regular expression with the given 278 * replacement 279 */ 280 public ValueBuilder regexReplaceAll(String regex, Expression replacement) { 281 Expression newExp = ExpressionBuilder.regexReplaceAll(expression, regex, replacement); 282 return onNewValueBuilder(newExp); 283 } 284 285 /** 286 * Converts the current value to the given type using the registered type 287 * converters 288 * 289 * @param type the type to convert the value to 290 * @return the current builder 291 */ 292 public ValueBuilder convertTo(Class<?> type) { 293 Expression newExp = ExpressionBuilder.convertToExpression(expression, type); 294 return onNewValueBuilder(newExp); 295 } 296 297 /** 298 * Converts the current value to a String using the registered type converters 299 * 300 * @return the current builder 301 */ 302 public ValueBuilder convertToString() { 303 return convertTo(String.class); 304 } 305 306 /** 307 * Appends the string evaluation of this expression with the given value 308 * 309 * @param value the value or expression to append 310 * @return the current builder 311 */ 312 public ValueBuilder append(Object value) { 313 Expression newExp = ExpressionBuilder.append(expression, asExpression(value)); 314 return onNewValueBuilder(newExp); 315 } 316 317 /** 318 * Prepends the string evaluation of this expression with the given value 319 * 320 * @param value the value or expression to prepend 321 * @return the current builder 322 */ 323 public ValueBuilder prepend(Object value) { 324 Expression newExp = ExpressionBuilder.prepend(expression, asExpression(value)); 325 return onNewValueBuilder(newExp); 326 } 327 328 /** 329 * Sorts the current value using the given comparator. The current value must be convertable 330 * to a {@link List} to allow sorting using the comparator. 331 * 332 * @param comparator the comparator used by sorting 333 * @return the current builder 334 */ 335 public ValueBuilder sort(Comparator<?> comparator) { 336 Expression newExp = ExpressionBuilder.sortExpression(expression, comparator); 337 return onNewValueBuilder(newExp); 338 } 339 340 /** 341 * Invokes the method with the given name (supports OGNL syntax). 342 * 343 * @param methodName name of method to invoke. 344 * @return the current builder 345 */ 346 public ValueBuilder method(String methodName) { 347 Expression newExp = ExpressionBuilder.ognlExpression(expression, methodName); 348 return onNewValueBuilder(newExp); 349 } 350 351 /** 352 * Negates the built expression. 353 * 354 * @return the current builder 355 */ 356 public ValueBuilder not() { 357 not = true; 358 return this; 359 } 360 361 // Implementation methods 362 // ------------------------------------------------------------------------- 363 364 /** 365 * A strategy method to allow derived classes to deal with the newly created 366 * predicate in different ways 367 */ 368 protected Predicate onNewPredicate(Predicate predicate) { 369 if (not) { 370 return PredicateBuilder.not(predicate); 371 } else { 372 return predicate; 373 } 374 } 375 376 protected Expression asExpression(Object value) { 377 if (value instanceof Expression) { 378 return (Expression)value; 379 } else { 380 return ExpressionBuilder.constantExpression(value); 381 } 382 } 383 384 protected ValueBuilder onNewValueBuilder(Expression exp) { 385 return new ValueBuilder(exp); 386 } 387}