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