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     */
017    package org.apache.camel.util;
018    
019    import org.apache.camel.RuntimeCamelException;
020    import org.apache.camel.converter.ObjectConverter;
021    import org.apache.commons.logging.Log;
022    import org.apache.commons.logging.LogFactory;
023    
024    import java.lang.annotation.Annotation;
025    import java.lang.reflect.InvocationTargetException;
026    import java.lang.reflect.Method;
027    import java.nio.charset.Charset;
028    import java.util.ArrayList;
029    import java.util.Collection;
030    import java.util.Iterator;
031    import java.util.List;
032    
033    /**
034     * A number of useful helper methods for working with Objects
035     * 
036     * @version $Revision: 564168 $
037     */
038    public class ObjectHelper {
039        private static final transient Log LOG = LogFactory.getLog(ObjectHelper.class);
040    
041        /**
042         * Utility classes should not have a public constructor.
043         */
044        private ObjectHelper() {        
045        }
046        
047        /**
048         * A helper method for comparing objects for equality while handling nulls
049         */
050        public static boolean equals(Object a, Object b) {
051            if (a == b) {
052                return true;
053            }
054            return a != null && b != null && a.equals(b);
055        }
056    
057        /**
058         * Returns true if the given object is equal to any of the expected value
059         * 
060         * @param expression
061         * @param s
062         * @param s1
063         * @return
064         */
065        public static boolean isEqualToAny(Object object, Object... values) {
066            for (Object value : values) {
067                if (equals(object, value)) {
068                    return true;
069                }
070            }
071            return false;
072        }
073    
074        /**
075         * A helper method for performing an ordered comparsion on the objects
076         * handling nulls and objects which do not handle sorting gracefully
077         */
078        public static int compare(Object a, Object b) {
079            if (a == b) {
080                return 0;
081            }
082            if (a == null) {
083                return -1;
084            }
085            if (b == null) {
086                return 1;
087            }
088            if (a instanceof Comparable) {
089                Comparable comparable = (Comparable)a;
090                return comparable.compareTo(b);
091            } else {
092                int answer = a.getClass().getName().compareTo(b.getClass().getName());
093                if (answer == 0) {
094                    answer = a.hashCode() - b.hashCode();
095                }
096                return answer;
097            }
098        }
099    
100        public static void notNull(Object value, String name) {
101            if (value == null) {
102                throw new IllegalArgumentException("No " + name + " specified");
103            }
104        }
105    
106        public static String[] splitOnCharacter(String value, String needle, int count) {
107            String rc[] = new String[count];
108            rc[0] = value;
109            for (int i = 1; i < count; i++) {
110                String v = rc[i - 1];
111                int p = v.indexOf(needle);
112                if (p < 0) {
113                    return rc;
114                }
115                rc[i - 1] = v.substring(0, p);
116                rc[i] = v.substring(p + 1);
117            }
118            return rc;
119        }
120    
121        /**
122         * Removes any starting characters on the given text which match the given
123         * character
124         * 
125         * @param text the string
126         * @param ch the initial characters to remove
127         * @return either the original string or the new substring
128         */
129        public static String removeStartingCharacters(String text, char ch) {
130            int idx = 0;
131            while (text.charAt(idx) == ch) {
132                idx++;
133            }
134            if (idx > 0) {
135                return text.substring(idx);
136            }
137            return text;
138        }
139    
140        /**
141         * Returns true if the collection contains the specified value
142         */
143        public static boolean contains(Object collectionOrArray, Object value) {
144            if (collectionOrArray instanceof Collection) {
145                Collection collection = (Collection)collectionOrArray;
146                return collection.contains(value);
147            } else {
148                Iterator iter = ObjectConverter.iterator(value);
149                while (iter.hasNext()) {
150                    if (equals(value, iter.next())) {
151                        return true;
152                    }
153                }
154                return false;
155            }
156        }
157    
158        /**
159         * Returns the predicate matching boolean on a {@link List} result set where
160         * if the first element is a boolean its value is used otherwise this method
161         * returns true if the collection is not empty
162         * 
163         * @returns true if the first element is a boolean and its value is true or
164         *          if the list is non empty
165         */
166        public static boolean matches(List list) {
167            if (!list.isEmpty()) {
168                Object value = list.get(0);
169                if (value instanceof Boolean) {
170                    Boolean flag = (Boolean)value;
171                    return flag.booleanValue();
172                } else {
173                    // lets assume non-empty results are true
174                    return true;
175                }
176            }
177            return false;
178        }
179    
180        public static boolean isNotNullAndNonEmpty(String text) {
181            return text != null && text.trim().length() > 0;
182        }
183    
184        public static boolean isNullOrBlank(String text) {
185            return text == null || text.trim().length() <= 0;
186        }
187    
188        /**
189         * A helper method to access a system property, catching any security
190         * exceptions
191         * 
192         * @param name the name of the system property required
193         * @param defaultValue the default value to use if the property is not
194         *                available or a security exception prevents access
195         * @return the system property value or the default value if the property is
196         *         not available or security does not allow its access
197         */
198        public static String getSystemProperty(String name, String defaultValue) {
199            try {
200                return System.getProperty(name, defaultValue);
201            } catch (Exception e) {
202                if (LOG.isDebugEnabled()) {
203                    LOG.debug("Caught security exception accessing system property: " + name + ". Reason: " + e,
204                              e);
205                }
206                return defaultValue;
207            }
208        }
209    
210        /**
211         * Returns the type name of the given type or null if the type variable is
212         * null
213         */
214        public static String name(Class type) {
215            return type != null ? type.getName() : null;
216        }
217    
218        /**
219         * Returns the type name of the given value
220         */
221        public static String className(Object value) {
222            return name(value != null ? value.getClass() : null);
223        }
224    
225        /**
226         * Attempts to load the given class name using the thread context class
227         * loader or the class loader used to load this class
228         * 
229         * @param name the name of the class to load
230         * @return the class or null if it could not be loaded
231         */
232        public static Class<?> loadClass(String name) {
233            return loadClass(name, ObjectHelper.class.getClassLoader());
234        }
235    
236        /**
237         * Attempts to load the given class name using the thread context class
238         * loader or the given class loader
239         * 
240         * @param name the name of the class to load
241         * @param loader the class loader to use after the thread context class
242         *                loader
243         * @return the class or null if it could not be loaded
244         */
245        public static Class<?> loadClass(String name, ClassLoader loader) {
246            ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
247            if (contextClassLoader != null) {
248                try {
249                    return contextClassLoader.loadClass(name);
250                } catch (ClassNotFoundException e) {
251                    try {
252                        return loader.loadClass(name);
253                    } catch (ClassNotFoundException e1) {
254                        LOG.debug("Could not find class: " + name + ". Reason: " + e);
255                    }
256                }
257            }
258            return null;
259        }
260    
261        /**
262         * A helper method to invoke a method via reflection and wrap any exceptions
263         * as {@link RuntimeCamelException} instances
264         * 
265         * @param method the method to invoke
266         * @param instance the object instance (or null for static methods)
267         * @param parameters the parameters to the method
268         * @return the result of the method invocation
269         */
270        public static Object invokeMethod(Method method, Object instance, Object... parameters) {
271            try {
272                return method.invoke(instance, parameters);
273            } catch (IllegalAccessException e) {
274                throw new RuntimeCamelException(e);
275            } catch (InvocationTargetException e) {
276                throw new RuntimeCamelException(e.getCause());
277            }
278        }
279    
280        /**
281         * Returns a list of methods which are annotated with the given annotation
282         * 
283         * @param type the type to reflect on
284         * @param annotationType the annotation type
285         * @return a list of the methods found
286         */
287        public static List<Method> findMethodsWithAnnotation(Class<?> type,
288                                                             Class<? extends Annotation> annotationType) {
289            List<Method> answer = new ArrayList<Method>();
290            do {
291                Method[] methods = type.getDeclaredMethods();
292                for (Method method : methods) {
293                    if (method.getAnnotation(annotationType) != null) {
294                        answer.add(method);
295                    }
296                }
297                type = type.getSuperclass();
298            } while (type != null);
299            return answer;
300        }
301    
302        /**
303         * Turns the given object arrays into a meaningful string
304         * 
305         * @param objects an array of objects or null
306         * @return a meaningful string
307         */
308        public static String asString(Object[] objects) {
309            if (objects == null) {
310                return "null";
311            } else {
312                StringBuffer buffer = new StringBuffer("{");
313                int counter = 0;
314                for (Object object : objects) {
315                    if (counter++ > 0) {
316                        buffer.append(", ");
317                    }
318                    String text = (object == null) ? "null" : object.toString();
319                    buffer.append(text);
320                }
321                buffer.append("}");
322                return buffer.toString();
323            }
324        }
325    
326        /**
327         * Returns true if a class is assignable from another class like the
328         * {@link Class#isAssignableFrom(Class)} method but which also includes
329         * coercion between primitive types to deal with Java 5 primitive type
330         * wrapping
331         */
332        public static boolean isAssignableFrom(Class a, Class b) {
333            a = convertPrimitiveTypeToWrapperType(a);
334            b = convertPrimitiveTypeToWrapperType(b);
335            return a.isAssignableFrom(b);
336        }
337    
338        /**
339         * Converts primitive types such as int to its wrapper type like
340         * {@link Integer}
341         */
342        public static Class convertPrimitiveTypeToWrapperType(Class type) {
343            Class rc = type;
344            if (type.isPrimitive()) {
345                if (type == int.class) {
346                    rc = Integer.class;
347                } else if (type == long.class) {
348                    rc = Long.class;
349                } else if (type == double.class) {
350                    rc = Double.class;
351                } else if (type == float.class) {
352                    rc = Float.class;
353                } else if (type == short.class) {
354                    rc = Short.class;
355                } else if (type == byte.class) {
356                    rc = Byte.class;
357                }
358            }
359            return rc;
360        }
361    
362        /**
363         * Helper method to return the default character set name
364         */
365        public static String getDefaultCharacterSet() {
366            return Charset.defaultCharset().name();
367        }
368    }