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 */ 017 package org.apache.camel.util; 018 019 import java.io.Closeable; 020 import java.io.File; 021 import java.io.FileNotFoundException; 022 import java.io.IOException; 023 import java.io.InputStream; 024 import java.lang.annotation.Annotation; 025 import java.lang.reflect.AnnotatedElement; 026 import java.lang.reflect.InvocationTargetException; 027 import java.lang.reflect.Method; 028 import java.nio.channels.ReadableByteChannel; 029 import java.nio.charset.Charset; 030 import java.util.ArrayList; 031 import java.util.Arrays; 032 import java.util.Collection; 033 import java.util.Collections; 034 import java.util.Iterator; 035 import java.util.List; 036 import java.util.Scanner; 037 038 import org.w3c.dom.Node; 039 import org.w3c.dom.NodeList; 040 041 import org.apache.camel.CamelExecutionException; 042 import org.apache.camel.Exchange; 043 import org.apache.camel.RuntimeCamelException; 044 import org.apache.camel.TypeConverter; 045 import org.apache.camel.component.file.GenericFile; 046 import org.apache.commons.logging.Log; 047 import org.apache.commons.logging.LogFactory; 048 049 /** 050 * A number of useful helper methods for working with Objects 051 * 052 * @version $Revision: 793935 $ 053 */ 054 public final class ObjectHelper { 055 private static final transient Log LOG = LogFactory.getLog(ObjectHelper.class); 056 057 /** 058 * Utility classes should not have a public constructor. 059 */ 060 private ObjectHelper() { 061 } 062 063 /** 064 * A helper method for comparing objects for equality in which it uses type coerce to coerce 065 * types between the left and right values. This allows you to equal test eg String and Integer as 066 * Camel will be able to coerce the types 067 */ 068 public static boolean typeCoerceEquals(TypeConverter converter, Object leftValue, Object rightValue) { 069 // try without type coerce 070 boolean answer = equal(leftValue, rightValue); 071 if (answer) { 072 return true; 073 } 074 075 if (leftValue == null || rightValue == null) { 076 // no reason to continue as the first equal did not match and now one of the values is null 077 // so it wont help to type coerece to a null type 078 return false; 079 } 080 081 // convert left to right 082 Object value = converter.convertTo(rightValue.getClass(), leftValue); 083 answer = equal(value, rightValue); 084 if (answer) { 085 return true; 086 } 087 088 // convert right to left 089 value = converter.convertTo(leftValue.getClass(), rightValue); 090 answer = equal(leftValue, value); 091 return answer; 092 } 093 094 /** 095 * A helper method for comparing objects for equality in which it uses type coerce to coerce 096 * types between the left and right values. This allows you to equal test eg String and Integer as 097 * Camel will be able to coerce the types 098 */ 099 public static boolean typeCoerceNotEquals(TypeConverter converter, Object leftValue, Object rightValue) { 100 return !typeCoerceEquals(converter, leftValue, rightValue); 101 } 102 103 /** 104 * A helper method for comparing objects ordering in which it uses type coerce to coerce 105 * types between the left and right values. This allows you to equal test eg String and Integer as 106 * Camel will be able to coerce the types 107 */ 108 @SuppressWarnings("unchecked") 109 public static int typeCoerceCompare(TypeConverter converter, Object leftValue, Object rightValue) { 110 if (rightValue instanceof Comparable) { 111 Object value = converter.convertTo(rightValue.getClass(), leftValue); 112 if (value != null) { 113 return ((Comparable) rightValue).compareTo(value) * -1; 114 } 115 } 116 117 if (leftValue instanceof Comparable) { 118 Object value = converter.convertTo(leftValue.getClass(), rightValue); 119 if (value != null) { 120 return ((Comparable) leftValue).compareTo(value); 121 } 122 } 123 124 // use regular compare 125 return compare(leftValue, rightValue); 126 } 127 128 /** 129 * A helper method for comparing objects for equality while handling nulls 130 */ 131 public static boolean equal(Object a, Object b) { 132 if (a == b) { 133 return true; 134 } 135 136 if (a instanceof byte[] && b instanceof byte[]) { 137 return equalByteArray((byte[])a, (byte[])b); 138 } 139 140 return a != null && b != null && a.equals(b); 141 } 142 143 /** 144 * A helper method for comparing byte arrays for equality while handling 145 * nulls 146 */ 147 public static boolean equalByteArray(byte[] a, byte[] b) { 148 if (a == b) { 149 return true; 150 } 151 152 // loop and compare each byte 153 if (a != null && b != null && a.length == b.length) { 154 for (int i = 0; i < a.length; i++) { 155 if (a[i] != b[i]) { 156 return false; 157 } 158 } 159 // all bytes are equal 160 return true; 161 } 162 163 return false; 164 } 165 166 /** 167 * Returns true if the given object is equal to any of the expected value 168 */ 169 public static boolean isEqualToAny(Object object, Object... values) { 170 for (Object value : values) { 171 if (equal(object, value)) { 172 return true; 173 } 174 } 175 return false; 176 } 177 178 /** 179 * A helper method for performing an ordered comparison on the objects 180 * handling nulls and objects which do not handle sorting gracefully 181 */ 182 public static int compare(Object a, Object b) { 183 return compare(a, b, false); 184 } 185 186 /** 187 * A helper method for performing an ordered comparison on the objects 188 * handling nulls and objects which do not handle sorting gracefully 189 * 190 * @param a the first object 191 * @param b the second object 192 * @param ignoreCase ignore case for string comparison 193 */ 194 @SuppressWarnings("unchecked") 195 public static int compare(Object a, Object b, boolean ignoreCase) { 196 if (a == b) { 197 return 0; 198 } 199 if (a == null) { 200 return -1; 201 } 202 if (b == null) { 203 return 1; 204 } 205 if (ignoreCase && a instanceof String && b instanceof String) { 206 return ((String) a).compareToIgnoreCase((String) b); 207 } 208 if (a instanceof Comparable) { 209 Comparable comparable = (Comparable)a; 210 return comparable.compareTo(b); 211 } else { 212 int answer = a.getClass().getName().compareTo(b.getClass().getName()); 213 if (answer == 0) { 214 answer = a.hashCode() - b.hashCode(); 215 } 216 return answer; 217 } 218 } 219 220 public static Boolean toBoolean(Object value) { 221 if (value instanceof Boolean) { 222 return (Boolean)value; 223 } 224 if (value instanceof String) { 225 return "true".equalsIgnoreCase(value.toString()) ? Boolean.TRUE : Boolean.FALSE; 226 } 227 if (value instanceof Integer) { 228 return (Integer)value > 0 ? Boolean.TRUE : Boolean.FALSE; 229 } 230 return null; 231 } 232 233 /** 234 * Asserts whether the value is <b>not</b> <tt>null</tt> 235 * 236 * @param value the value to test 237 * @param name the key that resolved the value 238 * @throws IllegalArgumentException is thrown if assertion fails 239 */ 240 public static void notNull(Object value, String name) { 241 if (value == null) { 242 throw new IllegalArgumentException(name + " must be specified"); 243 } 244 } 245 246 /** 247 * Asserts whether the value is <b>not</b> <tt>null</tt> 248 * 249 * @param value the value to test 250 * @param on additional description to indicate where this problem occured (appended as toString()) 251 * @param name the key that resolved the value 252 * @throws IllegalArgumentException is thrown if assertion fails 253 */ 254 public static void notNull(Object value, String name, Object on) { 255 if (on == null) { 256 notNull(value, name); 257 } else if (value == null) { 258 throw new IllegalArgumentException(name + " must be specified on: " + on); 259 } 260 } 261 262 /** 263 * Asserts whether the string is <b>not</b> empty. 264 * 265 * @param value the string to test 266 * @param name the key that resolved the value 267 * @throws IllegalArgumentException is thrown if assertion fails 268 */ 269 public static void notEmpty(String value, String name) { 270 if (isEmpty(value)) { 271 throw new IllegalArgumentException(name + " must be specified and not empty"); 272 } 273 } 274 275 /** 276 * Asserts whether the string is <b>not</b> empty. 277 * 278 * @param value the string to test 279 * @param on additional description to indicate where this problem occured (appended as toString()) 280 * @param name the key that resolved the value 281 * @throws IllegalArgumentException is thrown if assertion fails 282 */ 283 public static void notEmpty(String value, String name, Object on) { 284 if (on == null) { 285 notNull(value, name); 286 } else if (isEmpty(value)) { 287 throw new IllegalArgumentException(name + " must be specified and not empty on: " + on); 288 } 289 } 290 291 /** 292 * Tests whether the value is <tt>null</tt> or an empty string. 293 * 294 * @param value the value, if its a String it will be tested for text length as well 295 * @return true if empty 296 */ 297 public static boolean isEmpty(Object value) { 298 return !isNotEmpty(value); 299 } 300 301 /** 302 * Tests whether the value is <b>not</b> <tt>null</tt> or an empty string. 303 * 304 * @param value the value, if its a String it will be tested for text length as well 305 * @return true if <b>not</b> empty 306 */ 307 public static boolean isNotEmpty(Object value) { 308 if (value == null) { 309 return false; 310 } else if (value instanceof String) { 311 String text = (String) value; 312 return text.trim().length() > 0; 313 } else { 314 return true; 315 } 316 } 317 318 public static String[] splitOnCharacter(String value, String needle, int count) { 319 String rc[] = new String[count]; 320 rc[0] = value; 321 for (int i = 1; i < count; i++) { 322 String v = rc[i - 1]; 323 int p = v.indexOf(needle); 324 if (p < 0) { 325 return rc; 326 } 327 rc[i - 1] = v.substring(0, p); 328 rc[i] = v.substring(p + 1); 329 } 330 return rc; 331 } 332 333 /** 334 * Removes any starting characters on the given text which match the given 335 * character 336 * 337 * @param text the string 338 * @param ch the initial characters to remove 339 * @return either the original string or the new substring 340 */ 341 public static String removeStartingCharacters(String text, char ch) { 342 int idx = 0; 343 while (text.charAt(idx) == ch) { 344 idx++; 345 } 346 if (idx > 0) { 347 return text.substring(idx); 348 } 349 return text; 350 } 351 352 public static String capitalize(String text) { 353 if (text == null) { 354 return null; 355 } 356 int length = text.length(); 357 if (length == 0) { 358 return text; 359 } 360 String answer = text.substring(0, 1).toUpperCase(); 361 if (length > 1) { 362 answer += text.substring(1, length); 363 } 364 return answer; 365 } 366 367 public static String after(String text, String after) { 368 if (!text.contains(after)) { 369 return null; 370 } 371 return text.substring(text.indexOf(after) + after.length()); 372 } 373 374 public static String before(String text, String before) { 375 if (!text.contains(before)) { 376 return null; 377 } 378 return text.substring(0, text.indexOf(before)); 379 } 380 381 public static String between(String text, String after, String before) { 382 text = after(text, after); 383 if (text == null) { 384 return null; 385 } 386 return before(text, before); 387 } 388 389 /** 390 * Returns true if the collection contains the specified value 391 */ 392 @SuppressWarnings("unchecked") 393 public static boolean contains(Object collectionOrArray, Object value) { 394 if (collectionOrArray instanceof Collection) { 395 Collection collection = (Collection)collectionOrArray; 396 return collection.contains(value); 397 } else if (collectionOrArray instanceof String && value instanceof String) { 398 String str = (String)collectionOrArray; 399 String subStr = (String)value; 400 return str.contains(subStr); 401 } else { 402 Iterator iter = createIterator(collectionOrArray); 403 while (iter.hasNext()) { 404 if (equal(value, iter.next())) { 405 return true; 406 } 407 } 408 } 409 return false; 410 } 411 412 /** 413 * Creates an iterator over the value if the value is a collection, an 414 * Object[] or a primitive type array; otherwise to simplify the caller's 415 * code, we just create a singleton collection iterator over a single value 416 * <p/> 417 * Will default use comma for String separating String values. 418 * 419 * @param value the value 420 * @return the iterator 421 */ 422 public static Iterator createIterator(Object value) { 423 return createIterator(value, ","); 424 } 425 426 /** 427 * Creates an iterator over the value if the value is a collection, an 428 * Object[] or a primitive type array; otherwise to simplify the caller's 429 * code, we just create a singleton collection iterator over a single value 430 * 431 * @param value the value 432 * @param delimiter delimiter for separating String values 433 * @return the iterator 434 */ 435 @SuppressWarnings("unchecked") 436 public static Iterator createIterator(Object value, String delimiter) { 437 if (value == null) { 438 return Collections.EMPTY_LIST.iterator(); 439 } else if (value instanceof Iterator) { 440 return (Iterator)value; 441 } else if (value instanceof Collection) { 442 Collection collection = (Collection)value; 443 return collection.iterator(); 444 } else if (value.getClass().isArray()) { 445 // TODO we should handle primitive array types? 446 List<Object> list = Arrays.asList((Object[])value); 447 return list.iterator(); 448 } else if (value instanceof NodeList) { 449 // lets iterate through DOM results after performing XPaths 450 final NodeList nodeList = (NodeList)value; 451 return new Iterator<Node>() { 452 int idx = -1; 453 454 public boolean hasNext() { 455 return ++idx < nodeList.getLength(); 456 } 457 458 public Node next() { 459 return nodeList.item(idx); 460 } 461 462 public void remove() { 463 throw new UnsupportedOperationException(); 464 } 465 }; 466 } else if (value instanceof String) { 467 final String s = (String) value; 468 469 // this code is optimized to only use a Scanner if needed, eg there is a delimiter 470 471 if (s.contains(delimiter)) { 472 // use a scanner if it contains the delimtor 473 Scanner scanner = new Scanner((String)value); 474 scanner.useDelimiter(delimiter); 475 return scanner; 476 } else { 477 // use a plain iterator that returns the value as is as there are only a single value 478 return new Iterator<String>() { 479 int idx = -1; 480 481 public boolean hasNext() { 482 // empty string should not be regarded as having next 483 return ++idx == 0 && ObjectHelper.isNotEmpty(s); 484 } 485 486 public String next() { 487 return s; 488 } 489 490 public void remove() { 491 throw new UnsupportedOperationException(); 492 } 493 }; 494 } 495 } else { 496 return Collections.singletonList(value).iterator(); 497 } 498 } 499 500 /** 501 * Returns the predicate matching boolean on a {@link List} result set where 502 * if the first element is a boolean its value is used otherwise this method 503 * returns true if the collection is not empty 504 * 505 * @return <tt>true</tt> if the first element is a boolean and its value 506 * is true or if the list is non empty 507 */ 508 public static boolean matches(List list) { 509 if (!list.isEmpty()) { 510 Object value = list.get(0); 511 if (value instanceof Boolean) { 512 return (Boolean)value; 513 } else { 514 // lets assume non-empty results are true 515 return true; 516 } 517 } 518 return false; 519 } 520 521 /** 522 * A helper method to access a system property, catching any security 523 * exceptions 524 * 525 * @param name the name of the system property required 526 * @param defaultValue the default value to use if the property is not 527 * available or a security exception prevents access 528 * @return the system property value or the default value if the property is 529 * not available or security does not allow its access 530 */ 531 public static String getSystemProperty(String name, String defaultValue) { 532 try { 533 return System.getProperty(name, defaultValue); 534 } catch (Exception e) { 535 if (LOG.isDebugEnabled()) { 536 LOG.debug("Caught security exception accessing system property: " + name + ". Reason: " + e, e); 537 } 538 return defaultValue; 539 } 540 } 541 542 /** 543 * A helper method to access a boolean system property, catching any 544 * security exceptions 545 * 546 * @param name the name of the system property required 547 * @param defaultValue the default value to use if the property is not 548 * available or a security exception prevents access 549 * @return the boolean representation of the system property value or the 550 * default value if the property is not available or security does 551 * not allow its access 552 */ 553 public static boolean getSystemProperty(String name, Boolean defaultValue) { 554 String result = getSystemProperty(name, defaultValue.toString()); 555 return Boolean.parseBoolean(result); 556 } 557 558 /** 559 * Returns the type name of the given type or null if the type variable is 560 * null 561 */ 562 public static String name(Class type) { 563 return type != null ? type.getName() : null; 564 } 565 566 /** 567 * Returns the type name of the given value 568 */ 569 public static String className(Object value) { 570 return name(value != null ? value.getClass() : null); 571 } 572 573 /** 574 * Returns the canonical type name of the given value 575 */ 576 public static String classCanonicalName(Object value) { 577 if (value != null) { 578 return value.getClass().getCanonicalName(); 579 } else { 580 return null; 581 } 582 } 583 584 /** 585 * Attempts to load the given class name using the thread context class 586 * loader or the class loader used to load this class 587 * 588 * @param name the name of the class to load 589 * @return the class or null if it could not be loaded 590 */ 591 public static Class<?> loadClass(String name) { 592 return loadClass(name, ObjectHelper.class.getClassLoader()); 593 } 594 595 /** 596 * Attempts to load the given class name using the thread context class 597 * loader or the given class loader 598 * 599 * @param name the name of the class to load 600 * @param loader the class loader to use after the thread context class 601 * loader 602 * @return the class or null if it could not be loaded 603 */ 604 public static Class<?> loadClass(String name, ClassLoader loader) { 605 // must clean the name so its pure java name, eg remoing \n or whatever people can do in the Spring XML 606 name = normalizeClassName(name); 607 608 // special for byte[] as its common to use 609 if ("java.lang.byte[]".equals(name) || "byte[]".equals(name)) { 610 return byte[].class; 611 } 612 613 // try context class loader first 614 Class clazz = doLoadClass(name, Thread.currentThread().getContextClassLoader()); 615 if (clazz == null) { 616 // then the provided loader 617 clazz = doLoadClass(name, loader); 618 } 619 if (clazz == null) { 620 // and fallback to the loader the loaded the ObjectHelper class 621 clazz = doLoadClass(name, ObjectHelper.class.getClassLoader()); 622 } 623 624 if (clazz == null) { 625 LOG.warn("Cannot find class: " + name); 626 } 627 628 return clazz; 629 } 630 631 /** 632 * Loads the given class with the provided classloader (may be null). 633 * Will ignore any class not found and return null. 634 * 635 * @param name the name of the class to load 636 * @param loader a provided loader (may be null) 637 * @return the class, or null if it could not be loaded 638 */ 639 private static Class<?> doLoadClass(String name, ClassLoader loader) { 640 ObjectHelper.notEmpty(name, "name"); 641 if (loader == null) { 642 return null; 643 } 644 try { 645 if (LOG.isTraceEnabled()) { 646 LOG.trace("Loading class: " + name + " using classloader: " + loader); 647 } 648 return loader.loadClass(name); 649 } catch (ClassNotFoundException e) { 650 if (LOG.isTraceEnabled()) { 651 LOG.trace("Cannot load class: " + name + " using classloader: " + loader, e); 652 } 653 654 } 655 return null; 656 } 657 658 /** 659 * Attempts to load the given resource as a stream using the thread context 660 * class loader or the class loader used to load this class 661 * 662 * @param name the name of the resource to load 663 * @return the stream or null if it could not be loaded 664 */ 665 public static InputStream loadResourceAsStream(String name) { 666 InputStream in = null; 667 668 ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); 669 if (contextClassLoader != null) { 670 in = contextClassLoader.getResourceAsStream(name); 671 } 672 if (in == null) { 673 in = ObjectHelper.class.getClassLoader().getResourceAsStream(name); 674 } 675 676 return in; 677 } 678 679 /** 680 * A helper method to invoke a method via reflection and wrap any exceptions 681 * as {@link RuntimeCamelException} instances 682 * 683 * @param method the method to invoke 684 * @param instance the object instance (or null for static methods) 685 * @param parameters the parameters to the method 686 * @return the result of the method invocation 687 */ 688 public static Object invokeMethod(Method method, Object instance, Object... parameters) { 689 try { 690 return method.invoke(instance, parameters); 691 } catch (IllegalAccessException e) { 692 throw new RuntimeCamelException(e); 693 } catch (InvocationTargetException e) { 694 throw new RuntimeCamelException(e.getCause()); 695 } 696 } 697 698 /** 699 * Tests whether the target method overrides the source method. 700 * <p/> 701 * Tests whether they have the same name, return type, and parameter list. 702 * 703 * @param source the source method 704 * @param target the target method 705 * @return <tt>true</tt> if it override, <tt>false</tt> otherwise 706 */ 707 public static boolean isOverridingMethod(Method source, Method target) { 708 if (source.getName().equals(target.getName()) 709 && source.getReturnType().equals(target.getReturnType()) 710 && source.getParameterTypes().length == target.getParameterTypes().length) { 711 712 // test if parameter types is the same as well 713 for (int i = 0; i < source.getParameterTypes().length; i++) { 714 if (!(source.getParameterTypes()[i].equals(target.getParameterTypes()[i]))) { 715 return false; 716 } 717 } 718 719 // the have same name, return type and parameter list, so its overriding 720 return true; 721 } 722 723 return false; 724 } 725 726 /** 727 * Returns a list of methods which are annotated with the given annotation 728 * 729 * @param type the type to reflect on 730 * @param annotationType the annotation type 731 * @return a list of the methods found 732 */ 733 public static List<Method> findMethodsWithAnnotation(Class<?> type, 734 Class<? extends Annotation> annotationType) { 735 return findMethodsWithAnnotation(type, annotationType, false); 736 } 737 738 /** 739 * Returns a list of methods which are annotated with the given annotation 740 * 741 * @param type the type to reflect on 742 * @param annotationType the annotation type 743 * @param checkMetaAnnotations check for meta annotations 744 * @return a list of the methods found 745 */ 746 public static List<Method> findMethodsWithAnnotation(Class<?> type, 747 Class<? extends Annotation> annotationType, 748 boolean checkMetaAnnotations) { 749 List<Method> answer = new ArrayList<Method>(); 750 do { 751 Method[] methods = type.getDeclaredMethods(); 752 for (Method method : methods) { 753 if (hasAnnotation(method, annotationType, checkMetaAnnotations)) { 754 answer.add(method); 755 } 756 } 757 type = type.getSuperclass(); 758 } while (type != null); 759 return answer; 760 } 761 762 /** 763 * Checks if a Class or Method are annotated with the given annotation 764 * 765 * @param elem the Class or Method to reflect on 766 * @param annotationType the annotation type 767 * @param checkMetaAnnotations check for meta annotations 768 * @return true if annotations is present 769 */ 770 public static boolean hasAnnotation(AnnotatedElement elem, Class<? extends Annotation> annotationType, 771 boolean checkMetaAnnotations) { 772 if (elem.isAnnotationPresent(annotationType)) { 773 return true; 774 } 775 if (checkMetaAnnotations) { 776 for (Annotation a : elem.getAnnotations()) { 777 for (Annotation meta : a.annotationType().getAnnotations()) { 778 if (meta.annotationType().getName().equals(annotationType.getName())) { 779 return true; 780 } 781 } 782 } 783 } 784 return false; 785 } 786 787 /** 788 * Turns the given object arrays into a meaningful string 789 * 790 * @param objects an array of objects or null 791 * @return a meaningful string 792 */ 793 public static String asString(Object[] objects) { 794 if (objects == null) { 795 return "null"; 796 } else { 797 StringBuffer buffer = new StringBuffer("{"); 798 int counter = 0; 799 for (Object object : objects) { 800 if (counter++ > 0) { 801 buffer.append(", "); 802 } 803 String text = (object == null) ? "null" : object.toString(); 804 buffer.append(text); 805 } 806 buffer.append("}"); 807 return buffer.toString(); 808 } 809 } 810 811 /** 812 * Returns true if a class is assignable from another class like the 813 * {@link Class#isAssignableFrom(Class)} method but which also includes 814 * coercion between primitive types to deal with Java 5 primitive type 815 * wrapping 816 */ 817 public static boolean isAssignableFrom(Class a, Class b) { 818 a = convertPrimitiveTypeToWrapperType(a); 819 b = convertPrimitiveTypeToWrapperType(b); 820 return a.isAssignableFrom(b); 821 } 822 823 /** 824 * Converts primitive types such as int to its wrapper type like 825 * {@link Integer} 826 */ 827 public static Class convertPrimitiveTypeToWrapperType(Class type) { 828 Class rc = type; 829 if (type.isPrimitive()) { 830 if (type == int.class) { 831 rc = Integer.class; 832 } else if (type == long.class) { 833 rc = Long.class; 834 } else if (type == double.class) { 835 rc = Double.class; 836 } else if (type == float.class) { 837 rc = Float.class; 838 } else if (type == short.class) { 839 rc = Short.class; 840 } else if (type == byte.class) { 841 rc = Byte.class; 842 // TODO: Why is boolean disabled 843 /* 844 * } else if (type == boolean.class) { rc = Boolean.class; 845 */ 846 } 847 } 848 return rc; 849 } 850 851 /** 852 * Helper method to return the default character set name 853 */ 854 public static String getDefaultCharacterSet() { 855 return Charset.defaultCharset().name(); 856 } 857 858 /** 859 * Returns the Java Bean property name of the given method, if it is a 860 * setter 861 */ 862 public static String getPropertyName(Method method) { 863 String propertyName = method.getName(); 864 if (propertyName.startsWith("set") && method.getParameterTypes().length == 1) { 865 propertyName = propertyName.substring(3, 4).toLowerCase() + propertyName.substring(4); 866 } 867 return propertyName; 868 } 869 870 /** 871 * Returns true if the given collection of annotations matches the given 872 * type 873 */ 874 public static boolean hasAnnotation(Annotation[] annotations, Class<?> type) { 875 for (Annotation annotation : annotations) { 876 if (type.isInstance(annotation)) { 877 return true; 878 } 879 } 880 return false; 881 } 882 883 /** 884 * Closes the given resource if it is available, logging any closing 885 * exceptions to the given log 886 * 887 * @param closeable the object to close 888 * @param name the name of the resource 889 * @param log the log to use when reporting closure warnings 890 */ 891 public static void close(Closeable closeable, String name, Log log) { 892 if (closeable != null) { 893 try { 894 closeable.close(); 895 } catch (IOException e) { 896 if (log != null) { 897 log.warn("Cannot close: " + name + ". Reason: " + e, e); 898 } 899 } 900 } 901 } 902 903 /** 904 * Converts the given value to the required type or throw a meaningful exception 905 */ 906 @SuppressWarnings("unchecked") 907 public static <T> T cast(Class<T> toType, Object value) { 908 if (toType == boolean.class) { 909 return (T)cast(Boolean.class, value); 910 } else if (toType.isPrimitive()) { 911 Class newType = convertPrimitiveTypeToWrapperType(toType); 912 if (newType != toType) { 913 return (T)cast(newType, value); 914 } 915 } 916 try { 917 return toType.cast(value); 918 } catch (ClassCastException e) { 919 throw new IllegalArgumentException("Failed to convert: " + value + " to type: " 920 + toType.getName() + " due to: " + e, e); 921 } 922 } 923 924 /** 925 * A helper method to create a new instance of a type using the default 926 * constructor arguments. 927 */ 928 public static <T> T newInstance(Class<T> type) { 929 try { 930 return type.newInstance(); 931 } catch (InstantiationException e) { 932 throw new RuntimeCamelException(e); 933 } catch (IllegalAccessException e) { 934 throw new RuntimeCamelException(e); 935 } 936 } 937 938 /** 939 * A helper method to create a new instance of a type using the default 940 * constructor arguments. 941 */ 942 public static <T> T newInstance(Class<?> actualType, Class<T> expectedType) { 943 try { 944 Object value = actualType.newInstance(); 945 return cast(expectedType, value); 946 } catch (InstantiationException e) { 947 throw new RuntimeCamelException(e); 948 } catch (IllegalAccessException e) { 949 throw new RuntimeCamelException(e); 950 } 951 } 952 953 /** 954 * Returns true if the given name is a valid java identifier 955 */ 956 public static boolean isJavaIdentifier(String name) { 957 if (name == null) { 958 return false; 959 } 960 int size = name.length(); 961 if (size < 1) { 962 return false; 963 } 964 if (Character.isJavaIdentifierStart(name.charAt(0))) { 965 for (int i = 1; i < size; i++) { 966 if (!Character.isJavaIdentifierPart(name.charAt(i))) { 967 return false; 968 } 969 } 970 return true; 971 } 972 return false; 973 } 974 975 /** 976 * Returns the type of the given object or null if the value is null 977 */ 978 public static Object type(Object bean) { 979 return bean != null ? bean.getClass() : null; 980 } 981 982 /** 983 * Evaluate the value as a predicate which attempts to convert the value to 984 * a boolean otherwise true is returned if the value is not null 985 */ 986 public static boolean evaluateValuePredicate(Object value) { 987 if (value instanceof Boolean) { 988 return (Boolean)value; 989 } else if (value instanceof String) { 990 if ("true".equals(value)) { 991 return true; 992 } else if ("false".equals(value)) { 993 return false; 994 } 995 } 996 return value != null; 997 } 998 999 /** 1000 * Wraps the caused exception in a {@link RuntimeCamelException} if its not 1001 * already such an exception. 1002 * 1003 * @param e the caused exception 1004 * @return the wrapper exception 1005 */ 1006 public static RuntimeCamelException wrapRuntimeCamelException(Throwable e) { 1007 if (e instanceof RuntimeCamelException) { 1008 // don't double wrap 1009 return (RuntimeCamelException)e; 1010 } else { 1011 return new RuntimeCamelException(e); 1012 } 1013 } 1014 1015 /** 1016 * Wraps the caused exception in a {@link CamelExecutionException} if its not 1017 * already such an exception. 1018 * 1019 * @param e the caused exception 1020 * @return the wrapper exception 1021 */ 1022 public static CamelExecutionException wrapCamelExecutionException(Exchange exchange, Throwable e) { 1023 if (e instanceof CamelExecutionException) { 1024 // don't double wrap 1025 return (CamelExecutionException)e; 1026 } else { 1027 return new CamelExecutionException("Exception occured during execution", exchange, e); 1028 } 1029 } 1030 1031 /** 1032 * Cleans the string to pure java identifier so we can use it for loading class names. 1033 * <p/> 1034 * Especially from Sping DSL people can have \n \t or other characters that otherwise 1035 * would result in ClassNotFoundException 1036 * 1037 * @param name the class name 1038 * @return normalized classname that can be load by a class loader. 1039 */ 1040 public static String normalizeClassName(String name) { 1041 StringBuffer sb = new StringBuffer(name.length()); 1042 for (char ch : name.toCharArray()) { 1043 if (ch == '.' || ch == '[' || ch == ']' || Character.isJavaIdentifierPart(ch)) { 1044 sb.append(ch); 1045 } 1046 } 1047 return sb.toString(); 1048 } 1049 1050 /** 1051 * Creates an iterator to walk the exception from the bottom up 1052 * (the last caused by going upwards to the root exception). 1053 * 1054 * @param exception the exception 1055 * @return the iterator 1056 */ 1057 public static Iterator<Throwable> createExceptionIterator(Throwable exception) { 1058 return new ExceptionIterator(exception); 1059 } 1060 1061 /** 1062 * Creates a {@link Scanner} for scanning the given value. 1063 * 1064 * @param exchange the current exchange 1065 * @param value the value, typically the message IN body 1066 * @return the scanner, is newer <tt>null</tt> 1067 */ 1068 public static Scanner getScanner(Exchange exchange, Object value) { 1069 if (value instanceof GenericFile) { 1070 // generic file is just a wrapper for the real file so call again with the real file 1071 GenericFile gf = (GenericFile) value; 1072 return getScanner(exchange, gf.getFile()); 1073 } 1074 1075 String charset = exchange.getProperty(Exchange.CHARSET_NAME, String.class); 1076 Scanner scanner = null; 1077 if (value instanceof Readable) { 1078 scanner = new Scanner((Readable)value); 1079 } else if (value instanceof InputStream) { 1080 scanner = charset == null ? new Scanner((InputStream)value) : new Scanner((InputStream)value, charset); 1081 } else if (value instanceof File) { 1082 try { 1083 scanner = charset == null ? new Scanner((File)value) : new Scanner((File)value, charset); 1084 } catch (FileNotFoundException e) { 1085 throw new RuntimeCamelException(e); 1086 } 1087 } else if (value instanceof String) { 1088 scanner = new Scanner((String)value); 1089 } else if (value instanceof ReadableByteChannel) { 1090 scanner = charset == null ? new Scanner((ReadableByteChannel)value) : new Scanner((ReadableByteChannel)value, charset); 1091 } 1092 1093 if (scanner == null) { 1094 // value is not a suitable type, try to convert value to a string 1095 String text = exchange.getContext().getTypeConverter().convertTo(String.class, exchange, value); 1096 if (text != null) { 1097 scanner = new Scanner(text); 1098 } 1099 } 1100 1101 if (scanner == null) { 1102 scanner = new Scanner(""); 1103 } 1104 1105 return scanner; 1106 } 1107 1108 private static class ExceptionIterator implements Iterator<Throwable> { 1109 private List<Throwable> tree = new ArrayList<Throwable>(); 1110 private Iterator<Throwable> it; 1111 1112 public ExceptionIterator(Throwable exception) { 1113 Throwable current = exception; 1114 // spool to the bottom of the caused by tree 1115 while (current != null) { 1116 tree.add(current); 1117 current = current.getCause(); 1118 } 1119 1120 // reverse tree so we go from bottom to top 1121 Collections.reverse(tree); 1122 it = tree.iterator(); 1123 } 1124 1125 public boolean hasNext() { 1126 return it.hasNext(); 1127 } 1128 1129 public Throwable next() { 1130 return it.next(); 1131 } 1132 1133 public void remove() { 1134 it.remove(); 1135 } 1136 } 1137 1138 }