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