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