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.util.ArrayList;
028    import java.util.Collection;
029    import java.util.Iterator;
030    import java.util.List;
031    
032    /**
033     * @version $Revision: 534560 $
034     */
035    public class ObjectHelper {
036        private static final transient Log log = LogFactory.getLog(ObjectHelper.class);
037    
038        /**
039         * A helper method for comparing objects for equality while handling nulls
040         */
041        public static boolean equals(Object a, Object b) {
042            if (a == b) {
043                return true;
044            }
045            return a != null && b != null && a.equals(b);
046        }
047    
048        /**
049         * A helper method for performing an ordered comparsion on the objects
050         * handling nulls and objects which do not
051         * handle sorting gracefully
052         */
053        public static int compare(Object a, Object b) {
054            if (a == b) {
055                return 0;
056            }
057            if (a == null) {
058                return -1;
059            }
060            if (b == null) {
061                return 1;
062            }
063            if (a instanceof Comparable) {
064                Comparable comparable = (Comparable) a;
065                return comparable.compareTo(b);
066            }
067            else {
068                int answer = a.getClass().getName().compareTo(b.getClass().getName());
069                if (answer == 0) {
070                    answer = a.hashCode() - b.hashCode();
071                }
072                return answer;
073            }
074        }
075    
076        public static void notNull(Object value, String name) {
077            if (value == null) {
078                throw new IllegalArgumentException("No " + name + " specified");
079            }
080        }
081    
082        public static String[] splitOnCharacter(String value, String needle, int count) {
083            String rc[] = new String[count];
084            rc[0] = value;
085            for (int i = 1; i < count; i++) {
086                String v = rc[i - 1];
087                int p = v.indexOf(needle);
088                if (p < 0) {
089                    return rc;
090                }
091                rc[i - 1] = v.substring(0, p);
092                rc[i] = v.substring(p + 1);
093            }
094            return rc;
095        }
096    
097        /**
098         * Removes any starting characters on the given text which match the given character
099         *
100         * @param text the string
101         * @param ch   the initial characters to remove
102         * @return either the original string or the new substring
103         */
104        public static String removeStartingCharacters(String text, char ch) {
105            int idx = 0;
106            while (text.charAt(idx) == ch) {
107                idx++;
108            }
109            if (idx > 0) {
110                return text.substring(idx);
111            }
112            return text;
113        }
114    
115        /**
116         * Returns true if the collection contains the specified value
117         */
118        public static boolean contains(Object collectionOrArray, Object value) {
119            if (collectionOrArray instanceof Collection) {
120                Collection collection = (Collection) collectionOrArray;
121                return collection.contains(value);
122            }
123            else {
124                Iterator iter = ObjectConverter.iterator(value);
125                while (iter.hasNext()) {
126                    if (equals(value, iter.next())) {
127                        return true;
128                    }
129                }
130                return false;
131            }
132        }
133    
134        /**
135         * Returns the predicate matching boolean on a {@link List} result set
136         * where if the first element is a boolean its value is used
137         * otherwise this method returns true if the collection is not empty
138         *
139         * @returns true if the first element is a boolean and its value is true or if the list is non empty
140         */
141        public static boolean matches(List list) {
142            if (!list.isEmpty()) {
143                Object value = list.get(0);
144                if (value instanceof Boolean) {
145                    Boolean flag = (Boolean) value;
146                    return flag.booleanValue();
147                }
148                else {
149                    // lets assume non-empty results are true
150                    return true;
151                }
152            }
153            return false;
154        }
155    
156        public static boolean isNotNullOrBlank(String text) {
157            return text != null && text.trim().length() > 0;
158        }
159    
160        /**
161         * A helper method to access a system property, catching any security exceptions
162         *
163         * @param name         the name of the system property required
164         * @param defaultValue the default value to use if the property is not available or a security exception prevents access
165         * @return the system property value or the default value if the property is not available or security does not allow its access
166         */
167        public static String getSystemProperty(String name, String defaultValue) {
168            try {
169                return System.getProperty(name, defaultValue);
170            }
171            catch (Exception e) {
172                if (log.isDebugEnabled()) {
173                    log.debug("Caught security exception accessing system property: " + name + ". Reason: " + e, e);
174                }
175                return defaultValue;
176            }
177        }
178    
179        /**
180         * Returns the type name of the given type or null if the type variable is null
181         */
182        public static String name(Class type) {
183            return type != null ? type.getName() : null;
184        }
185    
186        /**
187         * Returns the type name of the given value
188         */
189        public static String className(Object value) {
190            return name(value != null ? value.getClass() : null);
191        }
192    
193        /**
194         * Attempts to load the given class name using the thread context class loader
195         * or the class loader used to load this class
196         *
197         * @param name the name of the class to load
198         * @return the class or null if it could not be loaded
199         */
200        public static Class<?> loadClass(String name) {
201            return loadClass(name, ObjectHelper.class.getClassLoader());
202        }
203    
204        /**
205         * Attempts to load the given class name using the thread context class loader or the given class loader
206         *
207         * @param name   the name of the class to load
208         * @param loader the class loader to use after the thread context class loader
209         * @return the class or null if it could not be loaded
210         */
211        public static Class<?> loadClass(String name, ClassLoader loader) {
212            ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
213            if (contextClassLoader != null) {
214                try {
215                    return contextClassLoader.loadClass(name);
216                }
217                catch (ClassNotFoundException e) {
218                    try {
219                        return loader.loadClass(name);
220                    }
221                    catch (ClassNotFoundException e1) {
222                        log.debug("Could not find class: " + name + ". Reason: " + e);
223                    }
224                }
225            }
226            return null;
227        }
228    
229        /**
230         * A helper method to invoke a method via reflection and wrap any exceptions
231         * as {@link RuntimeCamelException} instances
232         *
233         * @param method     the method to invoke
234         * @param instance   the object instance (or null for static methods)
235         * @param parameters the parameters to the method
236         * @return the result of the method invocation
237         */
238        public static Object invokeMethod(Method method, Object instance, Object... parameters) {
239            try {
240                return method.invoke(instance, parameters);
241            }
242            catch (IllegalAccessException e) {
243                throw new RuntimeCamelException(e);
244            }
245            catch (InvocationTargetException e) {
246                throw new RuntimeCamelException(e.getCause());
247            }
248        }
249    
250        /**
251         * Returns a list of methods which are annotated with the given annotation
252         *
253         * @param type           the type to reflect on
254         * @param annotationType the annotation type
255         * @return a list of the methods found
256         */
257        public static List<Method> findMethodsWithAnnotation(Class<?> type, Class<? extends Annotation> annotationType) {
258            List<Method> answer = new ArrayList<Method>();
259            do {
260                Method[] methods = type.getDeclaredMethods();
261                for (Method method : methods) {
262                    if (method.getAnnotation(annotationType) != null) {
263                        answer.add(method);
264                    }
265                }
266                type = type.getSuperclass();
267            }
268            while (type != null);
269            return answer;
270        }
271    
272        /**
273         * Turns the given object arrays into a meaningful string
274         *
275         * @param objects an array of objects or null
276         * @return a meaningful string
277         */
278        public static String asString(Object[] objects) {
279            if (objects == null) {
280                return "null";
281            }
282            else {
283                StringBuffer buffer = new StringBuffer("{");
284                int counter = 0;
285                for (Object object : objects) {
286                    if (counter++ > 0) {
287                        buffer.append(", ");
288                    }
289                    String text = (object == null) ? "null" : object.toString();
290                    buffer.append(text);
291                }
292                buffer.append("}");
293                return buffer.toString();
294            }
295        }
296    }