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