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 }