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