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