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