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