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.util; 018 019import java.io.Closeable; 020import java.io.File; 021import java.io.FileNotFoundException; 022import java.io.IOException; 023import java.io.InputStream; 024import java.lang.annotation.Annotation; 025import java.lang.reflect.AnnotatedElement; 026import java.lang.reflect.Array; 027import java.lang.reflect.Constructor; 028import java.lang.reflect.Field; 029import java.lang.reflect.InvocationTargetException; 030import java.lang.reflect.Method; 031import java.net.URL; 032import java.nio.channels.ReadableByteChannel; 033import java.nio.charset.Charset; 034import java.util.ArrayList; 035import java.util.Arrays; 036import java.util.Collection; 037import java.util.Collections; 038import java.util.Enumeration; 039import java.util.Iterator; 040import java.util.List; 041import java.util.Locale; 042import java.util.Map; 043import java.util.NoSuchElementException; 044import java.util.Objects; 045import java.util.Optional; 046import java.util.Properties; 047import java.util.Scanner; 048import java.util.concurrent.Callable; 049import java.util.function.Consumer; 050import java.util.function.Function; 051import java.util.function.Supplier; 052 053import org.w3c.dom.Node; 054import org.w3c.dom.NodeList; 055 056import org.apache.camel.CamelContext; 057import org.apache.camel.CamelExecutionException; 058import org.apache.camel.Exchange; 059import org.apache.camel.Message; 060import org.apache.camel.Ordered; 061import org.apache.camel.RuntimeCamelException; 062import org.apache.camel.TypeConverter; 063import org.apache.camel.WrappedFile; 064import org.apache.camel.util.function.ThrowingFunction; 065import org.slf4j.Logger; 066import org.slf4j.LoggerFactory; 067 068/** 069 * A number of useful helper methods for working with Objects 070 * 071 * @version 072 */ 073public final class ObjectHelper { 074 private static final Logger LOG = LoggerFactory.getLogger(ObjectHelper.class); 075 private static final String DEFAULT_DELIMITER = ","; 076 077 /** 078 * Utility classes should not have a public constructor. 079 */ 080 private ObjectHelper() { 081 } 082 083 /** 084 * A helper method for comparing objects for equality in which it uses type coercion to coerce 085 * types between the left and right values. This allows you test for equality for example with 086 * a String and Integer type as Camel will be able to coerce the types. 087 */ 088 public static boolean typeCoerceEquals(TypeConverter converter, Object leftValue, Object rightValue) { 089 return typeCoerceEquals(converter, leftValue, rightValue, false); 090 } 091 092 /** 093 * A helper method for comparing objects for equality in which it uses type coercion to coerce 094 * types between the left and right values. This allows you test for equality for example with 095 * a String and Integer type as Camel will be able to coerce the types. 096 */ 097 public static boolean typeCoerceEquals(TypeConverter converter, Object leftValue, Object rightValue, boolean ignoreCase) { 098 // sanity check 099 if (leftValue == null && rightValue == null) { 100 // they are equal 101 return true; 102 } else if (leftValue == null || rightValue == null) { 103 // only one of them is null so they are not equal 104 return false; 105 } 106 107 // try without type coerce 108 boolean answer = equal(leftValue, rightValue, ignoreCase); 109 if (answer) { 110 return true; 111 } 112 113 // are they same type, if so return false as the equals returned false 114 if (leftValue.getClass().isInstance(rightValue)) { 115 return false; 116 } 117 118 // convert left to right 119 Object value = converter.tryConvertTo(rightValue.getClass(), leftValue); 120 answer = equal(value, rightValue, ignoreCase); 121 if (answer) { 122 return true; 123 } 124 125 // convert right to left 126 value = converter.tryConvertTo(leftValue.getClass(), rightValue); 127 answer = equal(leftValue, value, ignoreCase); 128 return answer; 129 } 130 131 /** 132 * A helper method for comparing objects for inequality in which it uses type coercion to coerce 133 * types between the left and right values. This allows you test for inequality for example with 134 * a String and Integer type as Camel will be able to coerce the types. 135 */ 136 public static boolean typeCoerceNotEquals(TypeConverter converter, Object leftValue, Object rightValue) { 137 return !typeCoerceEquals(converter, leftValue, rightValue); 138 } 139 140 /** 141 * A helper method for comparing objects ordering in which it uses type coercion to coerce 142 * types between the left and right values. This allows you test for ordering for example with 143 * a String and Integer type as Camel will be able to coerce the types. 144 */ 145 @SuppressWarnings({"unchecked", "rawtypes"}) 146 public static int typeCoerceCompare(TypeConverter converter, Object leftValue, Object rightValue) { 147 148 // if both values is numeric then compare using numeric 149 Long leftNum = converter.tryConvertTo(Long.class, leftValue); 150 Long rightNum = converter.tryConvertTo(Long.class, rightValue); 151 if (leftNum != null && rightNum != null) { 152 return leftNum.compareTo(rightNum); 153 } 154 155 // also try with floating point numbers 156 Double leftDouble = converter.tryConvertTo(Double.class, leftValue); 157 Double rightDouble = converter.tryConvertTo(Double.class, rightValue); 158 if (leftDouble != null && rightDouble != null) { 159 return leftDouble.compareTo(rightDouble); 160 } 161 162 // prefer to NOT coerce to String so use the type which is not String 163 // for example if we are comparing String vs Integer then prefer to coerce to Integer 164 // as all types can be converted to String which does not work well for comparison 165 // as eg "10" < 6 would return true, where as 10 < 6 will return false. 166 // if they are both String then it doesn't matter 167 if (rightValue instanceof String && (!(leftValue instanceof String))) { 168 // if right is String and left is not then flip order (remember to * -1 the result then) 169 return typeCoerceCompare(converter, rightValue, leftValue) * -1; 170 } 171 172 // prefer to coerce to the right hand side at first 173 if (rightValue instanceof Comparable) { 174 Object value = converter.tryConvertTo(rightValue.getClass(), leftValue); 175 if (value != null) { 176 return ((Comparable) rightValue).compareTo(value) * -1; 177 } 178 } 179 180 // then fallback to the left hand side 181 if (leftValue instanceof Comparable) { 182 Object value = converter.tryConvertTo(leftValue.getClass(), rightValue); 183 if (value != null) { 184 return ((Comparable) leftValue).compareTo(value); 185 } 186 } 187 188 // use regular compare 189 return compare(leftValue, rightValue); 190 } 191 192 /** 193 * A helper method for comparing objects for equality while handling nulls 194 */ 195 public static boolean equal(Object a, Object b) { 196 return equal(a, b, false); 197 } 198 199 /** 200 * A helper method for comparing objects for equality while handling nulls 201 */ 202 public static boolean equal(final Object a, final Object b, final boolean ignoreCase) { 203 if (a == b) { 204 return true; 205 } 206 207 if (a == null || b == null) { 208 return false; 209 } 210 211 if (ignoreCase) { 212 if (a instanceof String && b instanceof String) { 213 return ((String) a).equalsIgnoreCase((String) b); 214 } 215 } 216 217 if (a.getClass().isArray() && b.getClass().isArray()) { 218 // uses array based equals 219 return Objects.deepEquals(a, b); 220 } else { 221 // use regular equals 222 return a.equals(b); 223 } 224 } 225 226 /** 227 * A helper method for comparing byte arrays for equality while handling 228 * nulls 229 */ 230 public static boolean equalByteArray(byte[] a, byte[] b) { 231 return Arrays.equals(a, b); 232 } 233 234 /** 235 * Returns true if the given object is equal to any of the expected value 236 */ 237 public static boolean isEqualToAny(Object object, Object... values) { 238 for (Object value : values) { 239 if (equal(object, value)) { 240 return true; 241 } 242 } 243 return false; 244 } 245 246 /** 247 * A helper method for performing an ordered comparison on the objects 248 * handling nulls and objects which do not handle sorting gracefully 249 */ 250 public static int compare(Object a, Object b) { 251 return compare(a, b, false); 252 } 253 254 /** 255 * A helper method for performing an ordered comparison on the objects 256 * handling nulls and objects which do not handle sorting gracefully 257 * 258 * @param a the first object 259 * @param b the second object 260 * @param ignoreCase ignore case for string comparison 261 */ 262 @SuppressWarnings({"unchecked", "rawtypes"}) 263 public static int compare(Object a, Object b, boolean ignoreCase) { 264 if (a == b) { 265 return 0; 266 } 267 if (a == null) { 268 return -1; 269 } 270 if (b == null) { 271 return 1; 272 } 273 if (a instanceof Ordered && b instanceof Ordered) { 274 return ((Ordered) a).getOrder() - ((Ordered) b).getOrder(); 275 } 276 if (ignoreCase && a instanceof String && b instanceof String) { 277 return ((String) a).compareToIgnoreCase((String) b); 278 } 279 if (a instanceof Comparable) { 280 Comparable comparable = (Comparable)a; 281 return comparable.compareTo(b); 282 } 283 int answer = a.getClass().getName().compareTo(b.getClass().getName()); 284 if (answer == 0) { 285 answer = a.hashCode() - b.hashCode(); 286 } 287 return answer; 288 } 289 290 public static Boolean toBoolean(Object value) { 291 if (value instanceof Boolean) { 292 return (Boolean)value; 293 } 294 if (value instanceof String) { 295 return Boolean.valueOf((String)value); 296 } 297 if (value instanceof Integer) { 298 return (Integer)value > 0 ? Boolean.TRUE : Boolean.FALSE; 299 } 300 return null; 301 } 302 303 /** 304 * Asserts whether the value is <b>not</b> <tt>null</tt> 305 * 306 * @param value the value to test 307 * @param name the key that resolved the value 308 * @return the passed {@code value} as is 309 * @throws IllegalArgumentException is thrown if assertion fails 310 */ 311 public static <T> T notNull(T value, String name) { 312 if (value == null) { 313 throw new IllegalArgumentException(name + " must be specified"); 314 } 315 316 return value; 317 } 318 319 /** 320 * Asserts whether the value is <b>not</b> <tt>null</tt> 321 * 322 * @param value the value to test 323 * @param on additional description to indicate where this problem occurred (appended as toString()) 324 * @param name the key that resolved the value 325 * @return the passed {@code value} as is 326 * @throws IllegalArgumentException is thrown if assertion fails 327 */ 328 public static <T> T notNull(T value, String name, Object on) { 329 if (on == null) { 330 notNull(value, name); 331 } else if (value == null) { 332 throw new IllegalArgumentException(name + " must be specified on: " + on); 333 } 334 335 return value; 336 } 337 338 /** 339 * Asserts whether the string is <b>not</b> empty. 340 * 341 * @param value the string to test 342 * @param name the key that resolved the value 343 * @return the passed {@code value} as is 344 * @throws IllegalArgumentException is thrown if assertion fails 345 * @deprecated use {@link StringHelper#notEmpty(String, String)} instead 346 */ 347 @Deprecated 348 public static String notEmpty(String value, String name) { 349 return StringHelper.notEmpty(value, name); 350 } 351 352 /** 353 * Asserts whether the string is <b>not</b> empty. 354 * 355 * @param value the string to test 356 * @param on additional description to indicate where this problem occurred 357 * (appended as toString()) 358 * @param name the key that resolved the value 359 * @return the passed {@code value} as is 360 * @throws IllegalArgumentException is thrown if assertion fails 361 * @deprecated use {@link StringHelper#notEmpty(String, String, Object)} 362 * instead 363 */ 364 @Deprecated 365 public static String notEmpty(String value, String name, Object on) { 366 return StringHelper.notEmpty(value, name, on); 367 } 368 369 /** 370 * Tests whether the value is <tt>null</tt> or an empty string. 371 * 372 * @param value the value, if its a String it will be tested for text length as well 373 * @return true if empty 374 */ 375 public static boolean isEmpty(Object value) { 376 return !isNotEmpty(value); 377 } 378 379 /** 380 * Tests whether the value is <b>not</b> <tt>null</tt>, an empty string or an empty collection/map. 381 * 382 * @param value the value, if its a String it will be tested for text length as well 383 * @return true if <b>not</b> empty 384 */ 385 @SuppressWarnings("unchecked") 386 public static boolean isNotEmpty(Object value) { 387 if (value == null) { 388 return false; 389 } else if (value instanceof String) { 390 String text = (String) value; 391 return text.trim().length() > 0; 392 } else if (value instanceof Collection) { 393 return !((Collection<?>)value).isEmpty(); 394 } else if (value instanceof Map) { 395 return !((Map<?, ?>)value).isEmpty(); 396 } else { 397 return true; 398 } 399 } 400 401 402 /** 403 * Returns the first non null object <tt>null</tt>. 404 * 405 * @param values the values 406 * @return an Optional 407 */ 408 public static Optional<Object> firstNotNull(Object... values) { 409 for (int i = 0; i < values.length; i++) { 410 if (values[i] != null) { 411 return Optional.of(values[i]); 412 } 413 } 414 415 return Optional.empty(); 416 } 417 418 /** 419 * Tests whether the value is <b>not</b> <tt>null</tt>, an empty string, an empty collection or a map 420 * 421 * @param value the value, if its a String it will be tested for text length as well 422 * @param consumer the consumer, the operation to be executed against value if not empty 423 */ 424 public static <T> void ifNotEmpty(T value, Consumer<T> consumer) { 425 if (isNotEmpty(value)) { 426 consumer.accept(value); 427 } 428 } 429 430 /** 431 * Tests whether the value is <b>not</b> <tt>null</tt>, an empty string, an empty collection or a map and transform it using the given function. 432 * 433 * @param value the value, if its a String it will be tested for text length as well 434 * @param function the function to be executed against value if not empty 435 */ 436 public static <I, R, T extends Throwable> Optional<R> applyIfNotEmpty(I value, ThrowingFunction<I, R, T> function) throws T { 437 if (isNotEmpty(value)) { 438 return Optional.ofNullable(function.apply(value)); 439 } 440 441 return Optional.empty(); 442 } 443 444 /** 445 * Tests whether the value is <b>not</b> <tt>null</tt>, an empty string, an empty collection or a map and transform it using the given function. 446 * 447 * @param value the value, if its a String it will be tested for text length as well 448 * @param consumer the function to be executed against value if not empty 449 * @param orElse the supplier to use to retrieve a result if the given value is empty 450 */ 451 public static <I, R, T extends Throwable> R applyIfNotEmpty(I value, ThrowingFunction<I, R, T> consumer, Supplier<R> orElse) throws T { 452 if (isNotEmpty(value)) { 453 return consumer.apply(value); 454 } 455 456 return orElse.get(); 457 } 458 459 /** 460 * @deprecated use 461 * {@link StringHelper#splitOnCharacter(String, String, int)} instead 462 */ 463 @Deprecated 464 public static String[] splitOnCharacter(String value, String needle, int count) { 465 return StringHelper.splitOnCharacter(value, needle, count); 466 } 467 468 /** 469 * Removes any starting characters on the given text which match the given 470 * character 471 * 472 * @param text the string 473 * @param ch the initial characters to remove 474 * @return either the original string or the new substring 475 * @deprecated use {@link StringHelper#removeStartingCharacters(String, char)} instead 476 */ 477 @Deprecated 478 public static String removeStartingCharacters(String text, char ch) { 479 return StringHelper.removeStartingCharacters(text, ch); 480 } 481 482 /** 483 * @deprecated use {@link StringHelper#capitalize(String)} instead 484 */ 485 @Deprecated 486 public static String capitalize(String text) { 487 return StringHelper.capitalize(text); 488 } 489 490 /** 491 * Returns the string after the given token 492 * 493 * @param text the text 494 * @param after the token 495 * @return the text after the token, or <tt>null</tt> if text does not contain the token 496 * @deprecated use {@link StringHelper#after(String, String)} instead 497 */ 498 @Deprecated 499 public static String after(String text, String after) { 500 return StringHelper.after(text, after); 501 } 502 503 /** 504 * Returns an object after the given token 505 * 506 * @param text the text 507 * @param after the token 508 * @param mapper a mapping function to convert the string after the token to 509 * type T 510 * @return an Optional describing the result of applying a mapping function 511 * to the text after the token. 512 * @deprecated use {@link StringHelper#after(String, String, Function) 513 * StringHelper.after(String, String, Function<String,T>)} 514 * instead 515 */ 516 @Deprecated 517 public static <T> Optional<T> after(String text, String after, Function<String, T> mapper) { 518 return StringHelper.after(text, after, mapper); 519 } 520 521 /** 522 * Returns the string before the given token 523 * 524 * @param text the text 525 * @param before the token 526 * @return the text before the token, or <tt>null</tt> if text does not contain the token 527 * @deprecated use {@link StringHelper#before(String, String)} instead 528 */ 529 @Deprecated 530 public static String before(String text, String before) { 531 return StringHelper.before(text, before); 532 } 533 534 /** 535 * Returns an object before the given token 536 * 537 * @param text the text 538 * @param before the token 539 * @param mapper a mapping function to convert the string before the token 540 * to type T 541 * @return an Optional describing the result of applying a mapping function 542 * to the text before the token. 543 * @deprecated use {@link StringHelper#before(String, String, Function) 544 * StringHelper.before(String, String, Function<String,T>)} 545 * instead 546 */ 547 @Deprecated 548 public static <T> Optional<T> before(String text, String before, Function<String, T> mapper) { 549 return StringHelper.before(text, before, mapper); 550 } 551 552 /** 553 * Returns the string between the given tokens 554 * 555 * @param text the text 556 * @param after the before token 557 * @param before the after token 558 * @return the text between the tokens, or <tt>null</tt> if text does not contain the tokens 559 * @deprecated use {@link StringHelper#between(String, String, String)} instead 560 */ 561 @Deprecated 562 public static String between(String text, String after, String before) { 563 return StringHelper.between(text, after, before); 564 } 565 566 /** 567 * Returns an object between the given token 568 * 569 * @param text the text 570 * @param after the before token 571 * @param before the after token 572 * @param mapper a mapping function to convert the string between the token to type T 573 * @return an Optional describing the result of applying a mapping function to the text between the token. 574 * @deprecated use {@link StringHelper#between(String, String, String, Function) 575 * StringHelper.between(String, String, String, Function<String,T>)} 576 * instead 577 */ 578 @Deprecated 579 public static <T> Optional<T> between(String text, String after, String before, Function<String, T> mapper) { 580 return StringHelper.between(text, after, before, mapper); 581 } 582 583 /** 584 * Returns the string between the most outer pair of tokens 585 * <p/> 586 * The number of token pairs must be evenly, eg there must be same number of before and after tokens, otherwise <tt>null</tt> is returned 587 * <p/> 588 * This implementation skips matching when the text is either single or double quoted. 589 * For example: 590 * <tt>${body.matches("foo('bar')")</tt> 591 * Will not match the parenthesis from the quoted text. 592 * 593 * @param text the text 594 * @param after the before token 595 * @param before the after token 596 * @return the text between the outer most tokens, or <tt>null</tt> if text does not contain the tokens 597 * @deprecated use {@link StringHelper#betweenOuterPair(String, char, char)} instead 598 */ 599 @Deprecated 600 public static String betweenOuterPair(String text, char before, char after) { 601 return StringHelper.betweenOuterPair(text, before, after); 602 } 603 604 /** 605 * Returns an object between the most outer pair of tokens 606 * 607 * @param text the text 608 * @param after the before token 609 * @param before the after token 610 * @param mapper a mapping function to convert the string between the most outer pair of tokens to type T 611 * @return an Optional describing the result of applying a mapping function to the text between the most outer pair of tokens. 612 * @deprecated use {@link StringHelper#betweenOuterPair(String, char, char, Function) 613 * StringHelper.betweenOuterPair(String, char, char, Function<String,T>)} 614 * instead 615 */ 616 @Deprecated 617 public static <T> Optional<T> betweenOuterPair(String text, char before, char after, Function<String, T> mapper) { 618 return StringHelper.betweenOuterPair(text, before, after, mapper); 619 } 620 621 /** 622 * Returns true if the collection contains the specified value 623 */ 624 public static boolean contains(Object collectionOrArray, Object value) { 625 // favor String types 626 if (collectionOrArray != null && (collectionOrArray instanceof StringBuffer || collectionOrArray instanceof StringBuilder)) { 627 collectionOrArray = collectionOrArray.toString(); 628 } 629 if (value != null && (value instanceof StringBuffer || value instanceof StringBuilder)) { 630 value = value.toString(); 631 } 632 633 if (collectionOrArray instanceof Collection) { 634 Collection<?> collection = (Collection<?>)collectionOrArray; 635 return collection.contains(value); 636 } else if (collectionOrArray instanceof String && value instanceof String) { 637 String str = (String)collectionOrArray; 638 String subStr = (String)value; 639 return str.contains(subStr); 640 } else { 641 Iterator<Object> iter = createIterator(collectionOrArray); 642 while (iter.hasNext()) { 643 if (equal(value, iter.next())) { 644 return true; 645 } 646 } 647 } 648 return false; 649 } 650 651 /** 652 * Creates an iterable over the value if the value is a collection, an 653 * Object[], a String with values separated by comma, 654 * or a primitive type array; otherwise to simplify the caller's code, 655 * we just create a singleton collection iterator over a single value 656 * <p/> 657 * Will default use comma for String separating String values. 658 * This method does <b>not</b> allow empty values 659 * 660 * @param value the value 661 * @return the iterable 662 */ 663 public static Iterable<Object> createIterable(Object value) { 664 return createIterable(value, DEFAULT_DELIMITER); 665 } 666 667 /** 668 * Creates an iterable over the value if the value is a collection, an 669 * Object[], a String with values separated by the given delimiter, 670 * or a primitive type array; otherwise to simplify the caller's 671 * code, we just create a singleton collection iterator over a single value 672 * <p/> 673 * This method does <b>not</b> allow empty values 674 * 675 * @param value the value 676 * @param delimiter delimiter for separating String values 677 * @return the iterable 678 */ 679 public static Iterable<Object> createIterable(Object value, String delimiter) { 680 return createIterable(value, delimiter, false); 681 } 682 683 /** 684 * Creates an iterator over the value if the value is a collection, an 685 * Object[], a String with values separated by comma, 686 * or a primitive type array; otherwise to simplify the caller's code, 687 * we just create a singleton collection iterator over a single value 688 * <p/> 689 * Will default use comma for String separating String values. 690 * This method does <b>not</b> allow empty values 691 * 692 * @param value the value 693 * @return the iterator 694 */ 695 public static Iterator<Object> createIterator(Object value) { 696 return createIterator(value, DEFAULT_DELIMITER); 697 } 698 699 /** 700 * Creates an iterator over the value if the value is a collection, an 701 * Object[], a String with values separated by the given delimiter, 702 * or a primitive type array; otherwise to simplify the caller's 703 * code, we just create a singleton collection iterator over a single value 704 * <p/> 705 * This method does <b>not</b> allow empty values 706 * 707 * @param value the value 708 * @param delimiter delimiter for separating String values 709 * @return the iterator 710 */ 711 public static Iterator<Object> createIterator(Object value, String delimiter) { 712 return createIterator(value, delimiter, false); 713 } 714 715 /** 716 * Creates an iterator over the value if the value is a collection, an 717 * Object[], a String with values separated by the given delimiter, 718 * or a primitive type array; otherwise to simplify the caller's 719 * code, we just create a singleton collection iterator over a single value 720 * 721 * </p> In case of primitive type arrays the returned {@code Iterator} iterates 722 * over the corresponding Java primitive wrapper objects of the given elements 723 * inside the {@code value} array. That's we get an autoboxing of the primitive 724 * types here for free as it's also the case in Java language itself. 725 * 726 * @param value the value 727 * @param delimiter delimiter for separating String values 728 * @param allowEmptyValues whether to allow empty values 729 * @return the iterator 730 */ 731 public static Iterator<Object> createIterator(Object value, String delimiter, boolean allowEmptyValues) { 732 return createIterable(value, delimiter, allowEmptyValues, false).iterator(); 733 } 734 735 /** 736 * Creates an iterator over the value if the value is a collection, an 737 * Object[], a String with values separated by the given delimiter, 738 * or a primitive type array; otherwise to simplify the caller's 739 * code, we just create a singleton collection iterator over a single value 740 * 741 * </p> In case of primitive type arrays the returned {@code Iterator} iterates 742 * over the corresponding Java primitive wrapper objects of the given elements 743 * inside the {@code value} array. That's we get an autoboxing of the primitive 744 * types here for free as it's also the case in Java language itself. 745 * 746 * @param value the value 747 * @param delimiter delimiter for separating String values 748 * @param allowEmptyValues whether to allow empty values 749 * @param pattern whether the delimiter is a pattern 750 * @return the iterator 751 */ 752 public static Iterator<Object> createIterator(Object value, String delimiter, 753 boolean allowEmptyValues, boolean pattern) { 754 return createIterable(value, delimiter, allowEmptyValues, pattern).iterator(); 755 } 756 757 /** 758 * Creates an iterable over the value if the value is a collection, an 759 * Object[], a String with values separated by the given delimiter, 760 * or a primitive type array; otherwise to simplify the caller's 761 * code, we just create a singleton collection iterator over a single value 762 * 763 * </p> In case of primitive type arrays the returned {@code Iterable} iterates 764 * over the corresponding Java primitive wrapper objects of the given elements 765 * inside the {@code value} array. That's we get an autoboxing of the primitive 766 * types here for free as it's also the case in Java language itself. 767 * 768 * @param value the value 769 * @param delimiter delimiter for separating String values 770 * @param allowEmptyValues whether to allow empty values 771 * @return the iterable 772 * @see java.lang.Iterable 773 */ 774 public static Iterable<Object> createIterable(Object value, String delimiter, 775 final boolean allowEmptyValues) { 776 return createIterable(value, delimiter, allowEmptyValues, false); 777 } 778 779 /** 780 * Creates an iterable over the value if the value is a collection, an 781 * Object[], a String with values separated by the given delimiter, 782 * or a primitive type array; otherwise to simplify the caller's 783 * code, we just create a singleton collection iterator over a single value 784 * 785 * </p> In case of primitive type arrays the returned {@code Iterable} iterates 786 * over the corresponding Java primitive wrapper objects of the given elements 787 * inside the {@code value} array. That's we get an autoboxing of the primitive 788 * types here for free as it's also the case in Java language itself. 789 * 790 * @param value the value 791 * @param delimiter delimiter for separating String values 792 * @param allowEmptyValues whether to allow empty values 793 * @param pattern whether the delimiter is a pattern 794 * @return the iterable 795 * @see java.lang.Iterable 796 */ 797 @SuppressWarnings("unchecked") 798 public static Iterable<Object> createIterable(Object value, String delimiter, 799 final boolean allowEmptyValues, final boolean pattern) { 800 801 // if its a message than we want to iterate its body 802 if (value instanceof Message) { 803 value = ((Message) value).getBody(); 804 } 805 806 if (value == null) { 807 return Collections.emptyList(); 808 } else if (value instanceof Iterator) { 809 final Iterator<Object> iterator = (Iterator<Object>)value; 810 return new Iterable<Object>() { 811 @Override 812 public Iterator<Object> iterator() { 813 return iterator; 814 } 815 }; 816 } else if (value instanceof Iterable) { 817 return (Iterable<Object>)value; 818 } else if (value.getClass().isArray()) { 819 if (isPrimitiveArrayType(value.getClass())) { 820 final Object array = value; 821 return new Iterable<Object>() { 822 @Override 823 public Iterator<Object> iterator() { 824 return new Iterator<Object>() { 825 private int idx; 826 827 public boolean hasNext() { 828 return idx < Array.getLength(array); 829 } 830 831 public Object next() { 832 if (!hasNext()) { 833 throw new NoSuchElementException("no more element available for '" + array + "' at the index " + idx); 834 } 835 836 return Array.get(array, idx++); 837 } 838 839 public void remove() { 840 throw new UnsupportedOperationException(); 841 } 842 }; 843 } 844 }; 845 } else { 846 return Arrays.asList((Object[]) value); 847 } 848 } else if (value instanceof NodeList) { 849 // lets iterate through DOM results after performing XPaths 850 final NodeList nodeList = (NodeList) value; 851 return new Iterable<Object>() { 852 @Override 853 public Iterator<Object> iterator() { 854 return new Iterator<Object>() { 855 private int idx; 856 857 public boolean hasNext() { 858 return idx < nodeList.getLength(); 859 } 860 861 public Object next() { 862 if (!hasNext()) { 863 throw new NoSuchElementException("no more element available for '" + nodeList + "' at the index " + idx); 864 } 865 866 return nodeList.item(idx++); 867 } 868 869 public void remove() { 870 throw new UnsupportedOperationException(); 871 } 872 }; 873 } 874 }; 875 } else if (value instanceof String) { 876 final String s = (String) value; 877 878 // this code is optimized to only use a Scanner if needed, eg there is a delimiter 879 880 if (delimiter != null && (pattern || s.contains(delimiter))) { 881 // use a scanner if it contains the delimiter or is a pattern 882 final Scanner scanner = new Scanner((String)value); 883 884 if (DEFAULT_DELIMITER.equals(delimiter)) { 885 // we use the default delimiter which is a comma, then cater for bean expressions with OGNL 886 // which may have balanced parentheses pairs as well. 887 // if the value contains parentheses we need to balance those, to avoid iterating 888 // in the middle of parentheses pair, so use this regular expression (a bit hard to read) 889 // the regexp will split by comma, but honor parentheses pair that may include commas 890 // as well, eg if value = "bean=foo?method=killer(a,b),bean=bar?method=great(a,b)" 891 // then the regexp will split that into two: 892 // -> bean=foo?method=killer(a,b) 893 // -> bean=bar?method=great(a,b) 894 // http://stackoverflow.com/questions/1516090/splitting-a-title-into-separate-parts 895 delimiter = ",(?!(?:[^\\(,]|[^\\)],[^\\)])+\\))"; 896 } 897 scanner.useDelimiter(delimiter); 898 899 return new Iterable<Object>() { 900 @Override 901 public Iterator<Object> iterator() { 902 return CastUtils.cast(scanner); 903 } 904 }; 905 } else { 906 return new Iterable<Object>() { 907 @Override 908 public Iterator<Object> iterator() { 909 // use a plain iterator that returns the value as is as there are only a single value 910 return new Iterator<Object>() { 911 private int idx; 912 913 public boolean hasNext() { 914 return idx == 0 && (allowEmptyValues || ObjectHelper.isNotEmpty(s)); 915 } 916 917 public Object next() { 918 if (!hasNext()) { 919 throw new NoSuchElementException("no more element available for '" + s + "' at the index " + idx); 920 } 921 922 idx++; 923 return s; 924 } 925 926 public void remove() { 927 throw new UnsupportedOperationException(); 928 } 929 }; 930 } 931 }; 932 } 933 } else { 934 return Collections.singletonList(value); 935 } 936 } 937 938 /** 939 * Returns the predicate matching boolean on a {@link List} result set where 940 * if the first element is a boolean its value is used otherwise this method 941 * returns true if the collection is not empty 942 * 943 * @return <tt>true</tt> if the first element is a boolean and its value 944 * is true or if the list is non empty 945 */ 946 public static boolean matches(List<?> list) { 947 if (!list.isEmpty()) { 948 Object value = list.get(0); 949 if (value instanceof Boolean) { 950 return (Boolean)value; 951 } else { 952 // lets assume non-empty results are true 953 return true; 954 } 955 } 956 return false; 957 } 958 959 /** 960 * A helper method to access a system property, catching any security exceptions 961 * 962 * @param name the name of the system property required 963 * @param defaultValue the default value to use if the property is not 964 * available or a security exception prevents access 965 * @return the system property value or the default value if the property is 966 * not available or security does not allow its access 967 */ 968 public static String getSystemProperty(String name, String defaultValue) { 969 try { 970 return System.getProperty(name, defaultValue); 971 } catch (Exception e) { 972 if (LOG.isDebugEnabled()) { 973 LOG.debug("Caught security exception accessing system property: " + name + ". Will use default value: " + defaultValue, e); 974 } 975 return defaultValue; 976 } 977 } 978 979 /** 980 * A helper method to access a boolean system property, catching any 981 * security exceptions 982 * 983 * @param name the name of the system property required 984 * @param defaultValue the default value to use if the property is not 985 * available or a security exception prevents access 986 * @return the boolean representation of the system property value or the 987 * default value if the property is not available or security does 988 * not allow its access 989 */ 990 public static boolean getSystemProperty(String name, Boolean defaultValue) { 991 String result = getSystemProperty(name, defaultValue.toString()); 992 return Boolean.parseBoolean(result); 993 } 994 995 /** 996 * A helper method to access a camel context properties with a prefix 997 * 998 * @param prefix the prefix 999 * @param camelContext the camel context 1000 * @return the properties which holds the camel context properties with the prefix, 1001 * and the key omit the prefix part 1002 */ 1003 public static Properties getCamelPropertiesWithPrefix(String prefix, CamelContext camelContext) { 1004 Properties answer = new Properties(); 1005 Map<String, String> camelProperties = camelContext.getGlobalOptions(); 1006 if (camelProperties != null) { 1007 for (Map.Entry<String, String> entry : camelProperties.entrySet()) { 1008 String key = entry.getKey(); 1009 if (key != null && key.startsWith(prefix)) { 1010 answer.put(key.substring(prefix.length()), entry.getValue()); 1011 } 1012 } 1013 } 1014 return answer; 1015 } 1016 1017 /** 1018 * Returns the type name of the given type or null if the type variable is 1019 * null 1020 */ 1021 public static String name(Class<?> type) { 1022 return type != null ? type.getName() : null; 1023 } 1024 1025 /** 1026 * Returns the type name of the given value 1027 */ 1028 public static String className(Object value) { 1029 return name(value != null ? value.getClass() : null); 1030 } 1031 1032 /** 1033 * Returns the canonical type name of the given value 1034 */ 1035 public static String classCanonicalName(Object value) { 1036 if (value != null) { 1037 return value.getClass().getCanonicalName(); 1038 } else { 1039 return null; 1040 } 1041 } 1042 1043 /** 1044 * Attempts to load the given class name using the thread context class 1045 * loader or the class loader used to load this class 1046 * 1047 * @param name the name of the class to load 1048 * @return the class or <tt>null</tt> if it could not be loaded 1049 */ 1050 public static Class<?> loadClass(String name) { 1051 return loadClass(name, ObjectHelper.class.getClassLoader()); 1052 } 1053 1054 /** 1055 * Attempts to load the given class name using the thread context class 1056 * loader or the given class loader 1057 * 1058 * @param name the name of the class to load 1059 * @param loader the class loader to use after the thread context class loader 1060 * @return the class or <tt>null</tt> if it could not be loaded 1061 */ 1062 public static Class<?> loadClass(String name, ClassLoader loader) { 1063 return loadClass(name, loader, false); 1064 } 1065 1066 /** 1067 * Attempts to load the given class name using the thread context class 1068 * loader or the given class loader 1069 * 1070 * @param name the name of the class to load 1071 * @param loader the class loader to use after the thread context class loader 1072 * @param needToWarn when <tt>true</tt> logs a warning when a class with the given name could not be loaded 1073 * @return the class or <tt>null</tt> if it could not be loaded 1074 */ 1075 public static Class<?> loadClass(String name, ClassLoader loader, boolean needToWarn) { 1076 // must clean the name so its pure java name, eg removing \n or whatever people can do in the Spring XML 1077 name = normalizeClassName(name); 1078 if (ObjectHelper.isEmpty(name)) { 1079 return null; 1080 } 1081 1082 // Try simple type first 1083 Class<?> clazz = loadSimpleType(name); 1084 if (clazz == null) { 1085 // try context class loader 1086 clazz = doLoadClass(name, Thread.currentThread().getContextClassLoader()); 1087 } 1088 if (clazz == null) { 1089 // then the provided loader 1090 clazz = doLoadClass(name, loader); 1091 } 1092 if (clazz == null) { 1093 // and fallback to the loader the loaded the ObjectHelper class 1094 clazz = doLoadClass(name, ObjectHelper.class.getClassLoader()); 1095 } 1096 1097 if (clazz == null) { 1098 if (needToWarn) { 1099 LOG.warn("Cannot find class: " + name); 1100 } else { 1101 LOG.debug("Cannot find class: " + name); 1102 } 1103 } 1104 1105 return clazz; 1106 } 1107 1108 1109 /** 1110 * Load a simple type 1111 * 1112 * @param name the name of the class to load 1113 * @return the class or <tt>null</tt> if it could not be loaded 1114 */ 1115 //CHECKSTYLE:OFF 1116 public static Class<?> loadSimpleType(String name) { 1117 // special for byte[] or Object[] as its common to use 1118 if ("java.lang.byte[]".equals(name) || "byte[]".equals(name)) { 1119 return byte[].class; 1120 } else if ("java.lang.Byte[]".equals(name) || "Byte[]".equals(name)) { 1121 return Byte[].class; 1122 } else if ("java.lang.Object[]".equals(name) || "Object[]".equals(name)) { 1123 return Object[].class; 1124 } else if ("java.lang.String[]".equals(name) || "String[]".equals(name)) { 1125 return String[].class; 1126 // and these is common as well 1127 } else if ("java.lang.String".equals(name) || "String".equals(name)) { 1128 return String.class; 1129 } else if ("java.lang.Boolean".equals(name) || "Boolean".equals(name)) { 1130 return Boolean.class; 1131 } else if ("boolean".equals(name)) { 1132 return boolean.class; 1133 } else if ("java.lang.Integer".equals(name) || "Integer".equals(name)) { 1134 return Integer.class; 1135 } else if ("int".equals(name)) { 1136 return int.class; 1137 } else if ("java.lang.Long".equals(name) || "Long".equals(name)) { 1138 return Long.class; 1139 } else if ("long".equals(name)) { 1140 return long.class; 1141 } else if ("java.lang.Short".equals(name) || "Short".equals(name)) { 1142 return Short.class; 1143 } else if ("short".equals(name)) { 1144 return short.class; 1145 } else if ("java.lang.Byte".equals(name) || "Byte".equals(name)) { 1146 return Byte.class; 1147 } else if ("byte".equals(name)) { 1148 return byte.class; 1149 } else if ("java.lang.Float".equals(name) || "Float".equals(name)) { 1150 return Float.class; 1151 } else if ("float".equals(name)) { 1152 return float.class; 1153 } else if ("java.lang.Double".equals(name) || "Double".equals(name)) { 1154 return Double.class; 1155 } else if ("double".equals(name)) { 1156 return double.class; 1157 } else if ("java.lang.Character".equals(name) || "Character".equals(name)) { 1158 return Character.class; 1159 } else if ("char".equals(name)) { 1160 return char.class; 1161 } 1162 return null; 1163 } 1164 //CHECKSTYLE:ON 1165 1166 /** 1167 * Loads the given class with the provided classloader (may be null). 1168 * Will ignore any class not found and return null. 1169 * 1170 * @param name the name of the class to load 1171 * @param loader a provided loader (may be null) 1172 * @return the class, or null if it could not be loaded 1173 */ 1174 private static Class<?> doLoadClass(String name, ClassLoader loader) { 1175 ObjectHelper.notEmpty(name, "name"); 1176 if (loader == null) { 1177 return null; 1178 } 1179 1180 try { 1181 LOG.trace("Loading class: {} using classloader: {}", name, loader); 1182 return loader.loadClass(name); 1183 } catch (ClassNotFoundException e) { 1184 if (LOG.isTraceEnabled()) { 1185 LOG.trace("Cannot load class: " + name + " using classloader: " + loader, e); 1186 } 1187 } 1188 1189 return null; 1190 } 1191 1192 /** 1193 * Attempts to load the given resource as a stream using the thread context 1194 * class loader or the class loader used to load this class 1195 * 1196 * @param name the name of the resource to load 1197 * @return the stream or null if it could not be loaded 1198 */ 1199 public static InputStream loadResourceAsStream(String name) { 1200 return loadResourceAsStream(name, null); 1201 } 1202 1203 /** 1204 * Attempts to load the given resource as a stream using the thread context 1205 * class loader or the class loader used to load this class 1206 * 1207 * @param name the name of the resource to load 1208 * @param loader optional classloader to attempt first 1209 * @return the stream or null if it could not be loaded 1210 */ 1211 public static InputStream loadResourceAsStream(String name, ClassLoader loader) { 1212 InputStream in = null; 1213 1214 String resolvedName = resolveUriPath(name); 1215 if (loader != null) { 1216 in = loader.getResourceAsStream(resolvedName); 1217 } 1218 if (in == null) { 1219 ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); 1220 if (contextClassLoader != null) { 1221 in = contextClassLoader.getResourceAsStream(resolvedName); 1222 } 1223 } 1224 if (in == null) { 1225 in = ObjectHelper.class.getClassLoader().getResourceAsStream(resolvedName); 1226 } 1227 if (in == null) { 1228 in = ObjectHelper.class.getResourceAsStream(resolvedName); 1229 } 1230 1231 return in; 1232 } 1233 1234 /** 1235 * Attempts to load the given resource as a stream using the thread context 1236 * class loader or the class loader used to load this class 1237 * 1238 * @param name the name of the resource to load 1239 * @return the stream or null if it could not be loaded 1240 */ 1241 public static URL loadResourceAsURL(String name) { 1242 return loadResourceAsURL(name, null); 1243 } 1244 1245 /** 1246 * Attempts to load the given resource as a stream using the thread context 1247 * class loader or the class loader used to load this class 1248 * 1249 * @param name the name of the resource to load 1250 * @param loader optional classloader to attempt first 1251 * @return the stream or null if it could not be loaded 1252 */ 1253 public static URL loadResourceAsURL(String name, ClassLoader loader) { 1254 URL url = null; 1255 1256 String resolvedName = resolveUriPath(name); 1257 if (loader != null) { 1258 url = loader.getResource(resolvedName); 1259 } 1260 if (url == null) { 1261 ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); 1262 if (contextClassLoader != null) { 1263 url = contextClassLoader.getResource(resolvedName); 1264 } 1265 } 1266 if (url == null) { 1267 url = ObjectHelper.class.getClassLoader().getResource(resolvedName); 1268 } 1269 if (url == null) { 1270 url = ObjectHelper.class.getResource(resolvedName); 1271 } 1272 1273 return url; 1274 } 1275 1276 /** 1277 * Attempts to load the given resources from the given package name using the thread context 1278 * class loader or the class loader used to load this class 1279 * 1280 * @param packageName the name of the package to load its resources 1281 * @return the URLs for the resources or null if it could not be loaded 1282 */ 1283 public static Enumeration<URL> loadResourcesAsURL(String packageName) { 1284 return loadResourcesAsURL(packageName, null); 1285 } 1286 1287 /** 1288 * Attempts to load the given resources from the given package name using the thread context 1289 * class loader or the class loader used to load this class 1290 * 1291 * @param packageName the name of the package to load its resources 1292 * @param loader optional classloader to attempt first 1293 * @return the URLs for the resources or null if it could not be loaded 1294 */ 1295 public static Enumeration<URL> loadResourcesAsURL(String packageName, ClassLoader loader) { 1296 Enumeration<URL> url = null; 1297 1298 if (loader != null) { 1299 try { 1300 url = loader.getResources(packageName); 1301 } catch (IOException e) { 1302 // ignore 1303 } 1304 } 1305 1306 if (url == null) { 1307 ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); 1308 if (contextClassLoader != null) { 1309 try { 1310 url = contextClassLoader.getResources(packageName); 1311 } catch (IOException e) { 1312 // ignore 1313 } 1314 } 1315 } 1316 if (url == null) { 1317 try { 1318 url = ObjectHelper.class.getClassLoader().getResources(packageName); 1319 } catch (IOException e) { 1320 // ignore 1321 } 1322 } 1323 1324 return url; 1325 } 1326 1327 /** 1328 * Helper operation used to remove relative path notation from 1329 * resources. Most critical for resources on the Classpath 1330 * as resource loaders will not resolve the relative paths correctly. 1331 * 1332 * @param name the name of the resource to load 1333 * @return the modified or unmodified string if there were no changes 1334 */ 1335 private static String resolveUriPath(String name) { 1336 // compact the path and use / as separator as that's used for loading resources on the classpath 1337 return FileUtil.compactPath(name, '/'); 1338 } 1339 1340 /** 1341 * A helper method to invoke a method via reflection and wrap any exceptions 1342 * as {@link RuntimeCamelException} instances 1343 * 1344 * @param method the method to invoke 1345 * @param instance the object instance (or null for static methods) 1346 * @param parameters the parameters to the method 1347 * @return the result of the method invocation 1348 */ 1349 public static Object invokeMethod(Method method, Object instance, Object... parameters) { 1350 try { 1351 return method.invoke(instance, parameters); 1352 } catch (IllegalAccessException e) { 1353 throw new RuntimeCamelException(e); 1354 } catch (InvocationTargetException e) { 1355 throw ObjectHelper.wrapRuntimeCamelException(e.getCause()); 1356 } 1357 } 1358 1359 /** 1360 * Tests whether the target method overrides the source method. 1361 * <p/> 1362 * Tests whether they have the same name, return type, and parameter list. 1363 * 1364 * @param source the source method 1365 * @param target the target method 1366 * @return <tt>true</tt> if it override, <tt>false</tt> otherwise 1367 */ 1368 public static boolean isOverridingMethod(Method source, Method target) { 1369 return isOverridingMethod(source, target, true); 1370 } 1371 1372 /** 1373 * Tests whether the target method overrides the source method. 1374 * <p/> 1375 * Tests whether they have the same name, return type, and parameter list. 1376 * 1377 * @param source the source method 1378 * @param target the target method 1379 * @param exact <tt>true</tt> if the override must be exact same types, <tt>false</tt> if the types should be assignable 1380 * @return <tt>true</tt> if it override, <tt>false</tt> otherwise 1381 */ 1382 public static boolean isOverridingMethod(Method source, Method target, boolean exact) { 1383 return isOverridingMethod(target.getDeclaringClass(), source, target, exact); 1384 } 1385 1386 /** 1387 * Tests whether the target method overrides the source method from the 1388 * inheriting class. 1389 * <p/> 1390 * Tests whether they have the same name, return type, and parameter list. 1391 * 1392 * @param inheritingClass the class inheriting the target method overriding 1393 * the source method 1394 * @param source the source method 1395 * @param target the target method 1396 * @param exact <tt>true</tt> if the override must be exact same types, 1397 * <tt>false</tt> if the types should be assignable 1398 * @return <tt>true</tt> if it override, <tt>false</tt> otherwise 1399 */ 1400 public static boolean isOverridingMethod(Class<?> inheritingClass, Method source, Method target, boolean exact) { 1401 1402 if (source.equals(target)) { 1403 return true; 1404 } else if (source.getDeclaringClass() == target.getDeclaringClass()) { 1405 return false; 1406 } else if (!source.getDeclaringClass().isAssignableFrom(inheritingClass) || !target.getDeclaringClass().isAssignableFrom(inheritingClass)) { 1407 return false; 1408 } 1409 1410 if (!source.getName().equals(target.getName())) { 1411 return false; 1412 } 1413 1414 if (exact) { 1415 if (!source.getReturnType().equals(target.getReturnType())) { 1416 return false; 1417 } 1418 } else { 1419 if (!source.getReturnType().isAssignableFrom(target.getReturnType())) { 1420 boolean b1 = source.isBridge(); 1421 boolean b2 = target.isBridge(); 1422 // must not be bridge methods 1423 if (!b1 && !b2) { 1424 return false; 1425 } 1426 } 1427 } 1428 1429 // must have same number of parameter types 1430 if (source.getParameterTypes().length != target.getParameterTypes().length) { 1431 return false; 1432 } 1433 1434 // test if parameter types is the same as well 1435 for (int i = 0; i < source.getParameterTypes().length; i++) { 1436 if (exact) { 1437 if (!(source.getParameterTypes()[i].equals(target.getParameterTypes()[i]))) { 1438 return false; 1439 } 1440 } else { 1441 if (!(source.getParameterTypes()[i].isAssignableFrom(target.getParameterTypes()[i]))) { 1442 boolean b1 = source.isBridge(); 1443 boolean b2 = target.isBridge(); 1444 // must not be bridge methods 1445 if (!b1 && !b2) { 1446 return false; 1447 } 1448 } 1449 } 1450 } 1451 1452 // the have same name, return type and parameter list, so its overriding 1453 return true; 1454 } 1455 1456 /** 1457 * Returns a list of methods which are annotated with the given annotation 1458 * 1459 * @param type the type to reflect on 1460 * @param annotationType the annotation type 1461 * @return a list of the methods found 1462 */ 1463 public static List<Method> findMethodsWithAnnotation(Class<?> type, 1464 Class<? extends Annotation> annotationType) { 1465 return findMethodsWithAnnotation(type, annotationType, false); 1466 } 1467 1468 /** 1469 * Returns a list of methods which are annotated with the given annotation 1470 * 1471 * @param type the type to reflect on 1472 * @param annotationType the annotation type 1473 * @param checkMetaAnnotations check for meta annotations 1474 * @return a list of the methods found 1475 */ 1476 public static List<Method> findMethodsWithAnnotation(Class<?> type, 1477 Class<? extends Annotation> annotationType, 1478 boolean checkMetaAnnotations) { 1479 List<Method> answer = new ArrayList<Method>(); 1480 do { 1481 Method[] methods = type.getDeclaredMethods(); 1482 for (Method method : methods) { 1483 if (hasAnnotation(method, annotationType, checkMetaAnnotations)) { 1484 answer.add(method); 1485 } 1486 } 1487 type = type.getSuperclass(); 1488 } while (type != null); 1489 return answer; 1490 } 1491 1492 /** 1493 * Checks if a Class or Method are annotated with the given annotation 1494 * 1495 * @param elem the Class or Method to reflect on 1496 * @param annotationType the annotation type 1497 * @param checkMetaAnnotations check for meta annotations 1498 * @return true if annotations is present 1499 */ 1500 public static boolean hasAnnotation(AnnotatedElement elem, Class<? extends Annotation> annotationType, 1501 boolean checkMetaAnnotations) { 1502 if (elem.isAnnotationPresent(annotationType)) { 1503 return true; 1504 } 1505 if (checkMetaAnnotations) { 1506 for (Annotation a : elem.getAnnotations()) { 1507 for (Annotation meta : a.annotationType().getAnnotations()) { 1508 if (meta.annotationType().getName().equals(annotationType.getName())) { 1509 return true; 1510 } 1511 } 1512 } 1513 } 1514 return false; 1515 } 1516 1517 /** 1518 * Turns the given object arrays into a meaningful string 1519 * 1520 * @param objects an array of objects or null 1521 * @return a meaningful string 1522 */ 1523 public static String asString(Object[] objects) { 1524 if (objects == null) { 1525 return "null"; 1526 } else { 1527 StringBuilder buffer = new StringBuilder("{"); 1528 int counter = 0; 1529 for (Object object : objects) { 1530 if (counter++ > 0) { 1531 buffer.append(", "); 1532 } 1533 String text = (object == null) ? "null" : object.toString(); 1534 buffer.append(text); 1535 } 1536 buffer.append("}"); 1537 return buffer.toString(); 1538 } 1539 } 1540 1541 /** 1542 * Returns true if a class is assignable from another class like the 1543 * {@link Class#isAssignableFrom(Class)} method but which also includes 1544 * coercion between primitive types to deal with Java 5 primitive type 1545 * wrapping 1546 */ 1547 public static boolean isAssignableFrom(Class<?> a, Class<?> b) { 1548 a = convertPrimitiveTypeToWrapperType(a); 1549 b = convertPrimitiveTypeToWrapperType(b); 1550 return a.isAssignableFrom(b); 1551 } 1552 1553 /** 1554 * Returns if the given {@code clazz} type is a Java primitive array type. 1555 * 1556 * @param clazz the Java type to be checked 1557 * @return {@code true} if the given type is a Java primitive array type 1558 */ 1559 public static boolean isPrimitiveArrayType(Class<?> clazz) { 1560 if (clazz != null && clazz.isArray()) { 1561 return clazz.getComponentType().isPrimitive(); 1562 } 1563 return false; 1564 } 1565 1566 public static int arrayLength(Object[] pojo) { 1567 return pojo.length; 1568 } 1569 1570 /** 1571 * Converts primitive types such as int to its wrapper type like 1572 * {@link Integer} 1573 */ 1574 public static Class<?> convertPrimitiveTypeToWrapperType(Class<?> type) { 1575 Class<?> rc = type; 1576 if (type.isPrimitive()) { 1577 if (type == int.class) { 1578 rc = Integer.class; 1579 } else if (type == long.class) { 1580 rc = Long.class; 1581 } else if (type == double.class) { 1582 rc = Double.class; 1583 } else if (type == float.class) { 1584 rc = Float.class; 1585 } else if (type == short.class) { 1586 rc = Short.class; 1587 } else if (type == byte.class) { 1588 rc = Byte.class; 1589 } else if (type == boolean.class) { 1590 rc = Boolean.class; 1591 } else if (type == char.class) { 1592 rc = Character.class; 1593 } 1594 } 1595 return rc; 1596 } 1597 1598 /** 1599 * Helper method to return the default character set name 1600 */ 1601 public static String getDefaultCharacterSet() { 1602 return Charset.defaultCharset().name(); 1603 } 1604 1605 /** 1606 * Returns the Java Bean property name of the given method, if it is a 1607 * setter 1608 */ 1609 public static String getPropertyName(Method method) { 1610 String propertyName = method.getName(); 1611 if (propertyName.startsWith("set") && method.getParameterTypes().length == 1) { 1612 propertyName = propertyName.substring(3, 4).toLowerCase(Locale.ENGLISH) + propertyName.substring(4); 1613 } 1614 return propertyName; 1615 } 1616 1617 /** 1618 * Returns true if the given collection of annotations matches the given type 1619 */ 1620 public static boolean hasAnnotation(Annotation[] annotations, Class<?> type) { 1621 for (Annotation annotation : annotations) { 1622 if (type.isInstance(annotation)) { 1623 return true; 1624 } 1625 } 1626 return false; 1627 } 1628 1629 /** 1630 * Gets the annotation from the given instance. 1631 * 1632 * @param instance the instance 1633 * @param type the annotation 1634 * @return the annotation, or <tt>null</tt> if the instance does not have the given annotation 1635 */ 1636 public static <A extends java.lang.annotation.Annotation> A getAnnotation(Object instance, Class<A> type) { 1637 return instance.getClass().getAnnotation(type); 1638 } 1639 1640 /** 1641 * Closes the given resource if it is available, logging any closing 1642 * exceptions to the given log 1643 * 1644 * @param closeable the object to close 1645 * @param name the name of the resource 1646 * @param log the log to use when reporting closure warnings 1647 * @deprecated will be removed in Camel 3.0. Instead use {@link org.apache.camel.util.IOHelper#close(java.io.Closeable, String, org.slf4j.Logger)} instead 1648 */ 1649 @Deprecated 1650 public static void close(Closeable closeable, String name, Logger log) { 1651 IOHelper.close(closeable, name, log); 1652 } 1653 1654 1655 /** 1656 * Converts the given value to the required type or throw a meaningful exception 1657 */ 1658 @SuppressWarnings("unchecked") 1659 public static <T> T cast(Class<T> toType, Object value) { 1660 if (toType == boolean.class) { 1661 return (T)cast(Boolean.class, value); 1662 } else if (toType.isPrimitive()) { 1663 Class<?> newType = convertPrimitiveTypeToWrapperType(toType); 1664 if (newType != toType) { 1665 return (T)cast(newType, value); 1666 } 1667 } 1668 try { 1669 return toType.cast(value); 1670 } catch (ClassCastException e) { 1671 throw new IllegalArgumentException("Failed to convert: " 1672 + value + " to type: " + toType.getName() + " due to: " + e, e); 1673 } 1674 } 1675 1676 /** 1677 * A helper method to create a new instance of a type using the default 1678 * constructor arguments. 1679 */ 1680 public static <T> T newInstance(Class<T> type) { 1681 try { 1682 return type.newInstance(); 1683 } catch (InstantiationException e) { 1684 throw new RuntimeCamelException(e); 1685 } catch (IllegalAccessException e) { 1686 throw new RuntimeCamelException(e); 1687 } 1688 } 1689 1690 /** 1691 * A helper method to create a new instance of a type using the default 1692 * constructor arguments. 1693 */ 1694 public static <T> T newInstance(Class<?> actualType, Class<T> expectedType) { 1695 try { 1696 Object value = actualType.newInstance(); 1697 return cast(expectedType, value); 1698 } catch (InstantiationException e) { 1699 throw new RuntimeCamelException(e); 1700 } catch (IllegalAccessException e) { 1701 throw new RuntimeCamelException(e); 1702 } 1703 } 1704 1705 /** 1706 * Does the given class have a default public no-arg constructor. 1707 */ 1708 public static boolean hasDefaultPublicNoArgConstructor(Class<?> type) { 1709 // getConstructors() returns only public constructors 1710 for (Constructor<?> ctr : type.getConstructors()) { 1711 if (ctr.getParameterTypes().length == 0) { 1712 return true; 1713 } 1714 } 1715 return false; 1716 } 1717 1718 /** 1719 * Returns true if the given name is a valid java identifier 1720 * @deprecated use {@link StringHelper#isJavaIdentifier(String)} instead 1721 */ 1722 @Deprecated 1723 public static boolean isJavaIdentifier(String name) { 1724 return StringHelper.isJavaIdentifier(name); 1725 } 1726 1727 /** 1728 * Returns the type of the given object or null if the value is null 1729 */ 1730 public static Object type(Object bean) { 1731 return bean != null ? bean.getClass() : null; 1732 } 1733 1734 /** 1735 * Evaluate the value as a predicate which attempts to convert the value to 1736 * a boolean otherwise true is returned if the value is not null 1737 */ 1738 public static boolean evaluateValuePredicate(Object value) { 1739 if (value instanceof Boolean) { 1740 return (Boolean)value; 1741 } else if (value instanceof String) { 1742 if ("true".equalsIgnoreCase((String)value)) { 1743 return true; 1744 } else if ("false".equalsIgnoreCase((String)value)) { 1745 return false; 1746 } 1747 } else if (value instanceof NodeList) { 1748 // is it an empty dom with empty attributes 1749 if (value instanceof Node && ((Node)value).hasAttributes()) { 1750 return true; 1751 } 1752 NodeList list = (NodeList) value; 1753 return list.getLength() > 0; 1754 } else if (value instanceof Collection) { 1755 // is it an empty collection 1756 Collection<?> col = (Collection<?>) value; 1757 return col.size() > 0; 1758 } 1759 return value != null; 1760 } 1761 1762 /** 1763 * Wraps the caused exception in a {@link RuntimeCamelException} if its not 1764 * already such an exception. 1765 * 1766 * @param e the caused exception 1767 * @return the wrapper exception 1768 */ 1769 public static RuntimeCamelException wrapRuntimeCamelException(Throwable e) { 1770 if (e instanceof RuntimeCamelException) { 1771 // don't double wrap 1772 return (RuntimeCamelException)e; 1773 } else { 1774 return new RuntimeCamelException(e); 1775 } 1776 } 1777 1778 /** 1779 * Wraps the caused exception in a {@link CamelExecutionException} if its not 1780 * already such an exception. 1781 * 1782 * @param e the caused exception 1783 * @return the wrapper exception 1784 */ 1785 public static CamelExecutionException wrapCamelExecutionException(Exchange exchange, Throwable e) { 1786 if (e instanceof CamelExecutionException) { 1787 // don't double wrap 1788 return (CamelExecutionException)e; 1789 } else { 1790 return new CamelExecutionException("Exception occurred during execution", exchange, e); 1791 } 1792 } 1793 1794 /** 1795 * Cleans the string to a pure Java identifier so we can use it for loading 1796 * class names. 1797 * <p/> 1798 * Especially from Spring DSL people can have \n \t or other characters that 1799 * otherwise would result in ClassNotFoundException 1800 * 1801 * @param name the class name 1802 * @return normalized classname that can be load by a class loader. 1803 * @deprecated use {@link StringHelper#normalizeClassName(String)} instead 1804 */ 1805 @Deprecated 1806 public static String normalizeClassName(String name) { 1807 return StringHelper.normalizeClassName(name); 1808 } 1809 1810 /** 1811 * Creates an Iterable to walk the exception from the bottom up 1812 * (the last caused by going upwards to the root exception). 1813 * 1814 * @see java.lang.Iterable 1815 * @param exception the exception 1816 * @return the Iterable 1817 */ 1818 public static Iterable<Throwable> createExceptionIterable(Throwable exception) { 1819 List<Throwable> throwables = new ArrayList<Throwable>(); 1820 1821 Throwable current = exception; 1822 // spool to the bottom of the caused by tree 1823 while (current != null) { 1824 throwables.add(current); 1825 current = current.getCause(); 1826 } 1827 Collections.reverse(throwables); 1828 1829 return throwables; 1830 } 1831 1832 /** 1833 * Creates an Iterator to walk the exception from the bottom up 1834 * (the last caused by going upwards to the root exception). 1835 * 1836 * @see Iterator 1837 * @param exception the exception 1838 * @return the Iterator 1839 */ 1840 public static Iterator<Throwable> createExceptionIterator(Throwable exception) { 1841 return createExceptionIterable(exception).iterator(); 1842 } 1843 1844 /** 1845 * Retrieves the given exception type from the exception. 1846 * <p/> 1847 * Is used to get the caused exception that typically have been wrapped in some sort 1848 * of Camel wrapper exception 1849 * <p/> 1850 * The strategy is to look in the exception hierarchy to find the first given cause that matches the type. 1851 * Will start from the bottom (the real cause) and walk upwards. 1852 * 1853 * @param type the exception type wanted to retrieve 1854 * @param exception the caused exception 1855 * @return the exception found (or <tt>null</tt> if not found in the exception hierarchy) 1856 */ 1857 public static <T> T getException(Class<T> type, Throwable exception) { 1858 if (exception == null) { 1859 return null; 1860 } 1861 1862 //check the suppressed exception first 1863 for (Throwable throwable : exception.getSuppressed()) { 1864 if (type.isInstance(throwable)) { 1865 return type.cast(throwable); 1866 } 1867 } 1868 1869 // walk the hierarchy and look for it 1870 for (final Throwable throwable : createExceptionIterable(exception)) { 1871 if (type.isInstance(throwable)) { 1872 return type.cast(throwable); 1873 } 1874 } 1875 1876 // not found 1877 return null; 1878 } 1879 1880 /** 1881 * Creates a {@link Scanner} for scanning the given value. 1882 * 1883 * @param exchange the current exchange 1884 * @param value the value, typically the message IN body 1885 * @return the scanner, is newer <tt>null</tt> 1886 */ 1887 public static Scanner getScanner(Exchange exchange, Object value) { 1888 if (value instanceof WrappedFile) { 1889 WrappedFile<?> gf = (WrappedFile<?>) value; 1890 Object body = gf.getBody(); 1891 if (body != null) { 1892 // we have loaded the file content into the body so use that 1893 value = body; 1894 } else { 1895 // generic file is just a wrapper for the real file so call again with the real file 1896 return getScanner(exchange, gf.getFile()); 1897 } 1898 } 1899 1900 String charset = exchange.getProperty(Exchange.CHARSET_NAME, String.class); 1901 1902 Scanner scanner = null; 1903 if (value instanceof Readable) { 1904 scanner = new Scanner((Readable)value); 1905 } else if (value instanceof InputStream) { 1906 scanner = charset == null ? new Scanner((InputStream)value) : new Scanner((InputStream)value, charset); 1907 } else if (value instanceof File) { 1908 try { 1909 scanner = charset == null ? new Scanner((File)value) : new Scanner((File)value, charset); 1910 } catch (FileNotFoundException e) { 1911 throw new RuntimeCamelException(e); 1912 } 1913 } else if (value instanceof String) { 1914 scanner = new Scanner((String)value); 1915 } else if (value instanceof ReadableByteChannel) { 1916 scanner = charset == null ? new Scanner((ReadableByteChannel)value) : new Scanner((ReadableByteChannel)value, charset); 1917 } 1918 1919 if (scanner == null) { 1920 // value is not a suitable type, try to convert value to a string 1921 String text = exchange.getContext().getTypeConverter().convertTo(String.class, exchange, value); 1922 if (text != null) { 1923 scanner = new Scanner(text); 1924 } 1925 } 1926 1927 if (scanner == null) { 1928 scanner = new Scanner(""); 1929 } 1930 1931 return scanner; 1932 } 1933 1934 public static String getIdentityHashCode(Object object) { 1935 return "0x" + Integer.toHexString(System.identityHashCode(object)); 1936 } 1937 1938 /** 1939 * Lookup the constant field on the given class with the given name 1940 * 1941 * @param clazz the class 1942 * @param name the name of the field to lookup 1943 * @return the value of the constant field, or <tt>null</tt> if not found 1944 */ 1945 public static String lookupConstantFieldValue(Class<?> clazz, String name) { 1946 if (clazz == null) { 1947 return null; 1948 } 1949 1950 // remove leading dots 1951 if (name.startsWith(",")) { 1952 name = name.substring(1); 1953 } 1954 1955 for (Field field : clazz.getFields()) { 1956 if (field.getName().equals(name)) { 1957 try { 1958 Object v = field.get(null); 1959 return v.toString(); 1960 } catch (IllegalAccessException e) { 1961 // ignore 1962 return null; 1963 } 1964 } 1965 } 1966 1967 return null; 1968 } 1969 1970 /** 1971 * Is the given value a numeric NaN type 1972 * 1973 * @param value the value 1974 * @return <tt>true</tt> if its a {@link Float#NaN} or {@link Double#NaN}. 1975 */ 1976 public static boolean isNaN(Object value) { 1977 if (value == null || !(value instanceof Number)) { 1978 return false; 1979 } 1980 // value must be a number 1981 return value.equals(Float.NaN) || value.equals(Double.NaN); 1982 } 1983 1984 /** 1985 * Calling the Callable with the setting of TCCL with the camel context application classloader. 1986 * 1987 * @param call the Callable instance 1988 * @param exchange the exchange 1989 * @return the result of Callable return 1990 */ 1991 public static Object callWithTCCL(Callable<?> call, Exchange exchange) throws Exception { 1992 ClassLoader apcl = null; 1993 if (exchange != null && exchange.getContext() != null) { 1994 apcl = exchange.getContext().getApplicationContextClassLoader(); 1995 } 1996 return callWithTCCL(call, apcl); 1997 } 1998 1999 /** 2000 * Calling the Callable with the setting of TCCL with a given classloader. 2001 * 2002 * @param call the Callable instance 2003 * @param classloader the class loader 2004 * @return the result of Callable return 2005 */ 2006 public static Object callWithTCCL(Callable<?> call, ClassLoader classloader) throws Exception { 2007 ClassLoader tccl = Thread.currentThread().getContextClassLoader(); 2008 try { 2009 if (classloader != null) { 2010 Thread.currentThread().setContextClassLoader(classloader); 2011 } 2012 return call.call(); 2013 } finally { 2014 if (tccl != null) { 2015 Thread.currentThread().setContextClassLoader(tccl); 2016 } 2017 } 2018 } 2019 2020}