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