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