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