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