Coverage Report - org.mule.util.ClassUtils
 
Classes in this File Line Coverage Branch Coverage Complexity
ClassUtils
0%
0/235
0%
0/188
0
ClassUtils$1
0%
0/3
0%
0/2
0
ClassUtils$10
0%
0/4
N/A
0
ClassUtils$2
0%
0/2
N/A
0
ClassUtils$3
0%
0/2
N/A
0
ClassUtils$4
0%
0/5
0%
0/2
0
ClassUtils$5
0%
0/4
N/A
0
ClassUtils$6
0%
0/4
N/A
0
ClassUtils$7
0%
0/5
0%
0/2
0
ClassUtils$8
0%
0/4
N/A
0
ClassUtils$9
0%
0/4
N/A
0
 
 1  
 /*
 2  
  * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
 3  
  * The software in this package is published under the terms of the CPAL v1.0
 4  
  * license, a copy of which has been included with this distribution in the
 5  
  * LICENSE.txt file.
 6  
  */
 7  
 package org.mule.util;
 8  
 
 9  
 import org.mule.routing.filters.WildcardFilter;
 10  
 
 11  
 import java.io.BufferedReader;
 12  
 import java.io.CharArrayReader;
 13  
 import java.io.IOException;
 14  
 import java.io.Reader;
 15  
 import java.lang.reflect.Constructor;
 16  
 import java.lang.reflect.InvocationTargetException;
 17  
 import java.lang.reflect.Method;
 18  
 import java.lang.reflect.Modifier;
 19  
 import java.net.URL;
 20  
 import java.net.URLClassLoader;
 21  
 import java.security.AccessController;
 22  
 import java.security.CodeSource;
 23  
 import java.security.PrivilegedAction;
 24  
 import java.util.ArrayList;
 25  
 import java.util.Collection;
 26  
 import java.util.Collections;
 27  
 import java.util.Enumeration;
 28  
 import java.util.HashMap;
 29  
 import java.util.HashSet;
 30  
 import java.util.Iterator;
 31  
 import java.util.List;
 32  
 import java.util.Map;
 33  
 import java.util.Set;
 34  
 
 35  
 /**
 36  
  * Extend the Apache Commons ClassUtils to provide additional functionality.
 37  
  * <p/>
 38  
  * <p>This class is useful for loading resources and classes in a fault tolerant manner
 39  
  * that works across different applications servers. The resource and classloading
 40  
  * methods are SecurityManager friendly.</p>
 41  
  */
 42  
 // @ThreadSafe
 43  0
 public class ClassUtils extends org.apache.commons.lang.ClassUtils
 44  
 {
 45  0
     public static final Object[] NO_ARGS = new Object[]{};
 46  0
     public static final Class<?>[] NO_ARGS_TYPE = new Class<?>[]{};
 47  
 
 48  0
     private static final Map<Class<?>, Class<?>> wrapperToPrimitiveMap = new HashMap<Class<?>, Class<?>>();
 49  0
     private static final Map<String, Class<?>> primitiveTypeNameMap = new HashMap<String, Class<?>>(32);
 50  
 
 51  
     static
 52  
     {
 53  0
         wrapperToPrimitiveMap.put(Boolean.class, Boolean.TYPE);
 54  0
         wrapperToPrimitiveMap.put(Byte.class, Byte.TYPE);
 55  0
         wrapperToPrimitiveMap.put(Character.class, Character.TYPE);
 56  0
         wrapperToPrimitiveMap.put(Short.class, Short.TYPE);
 57  0
         wrapperToPrimitiveMap.put(Integer.class, Integer.TYPE);
 58  0
         wrapperToPrimitiveMap.put(Long.class, Long.TYPE);
 59  0
         wrapperToPrimitiveMap.put(Double.class, Double.TYPE);
 60  0
         wrapperToPrimitiveMap.put(Float.class, Float.TYPE);
 61  0
         wrapperToPrimitiveMap.put(Void.TYPE, Void.TYPE);
 62  
 
 63  0
         Set<Class<?>> primitiveTypes = new HashSet<Class<?>>(32);
 64  0
         primitiveTypes.addAll(wrapperToPrimitiveMap.values());
 65  0
         for (Class<?> primitiveType : primitiveTypes)
 66  
         {
 67  0
             primitiveTypeNameMap.put(primitiveType.getName(), primitiveType);
 68  
         }
 69  0
     }
 70  
 
 71  
     public static boolean isConcrete(Class<?> clazz)
 72  
     {
 73  0
         if (clazz == null)
 74  
         {
 75  0
             throw new IllegalArgumentException("clazz may not be null");
 76  
         }
 77  0
         return !(clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers()));
 78  
     }
 79  
 
 80  
     /**
 81  
      * Load a given resource. <p/> This method will try to load the resource using
 82  
      * the following methods (in order):
 83  
      * <ul>
 84  
      * <li>From
 85  
      * {@link Thread#getContextClassLoader() Thread.currentThread().getContextClassLoader()}
 86  
      * <li>From
 87  
      * {@link Class#getClassLoader() ClassUtils.class.getClassLoader()}
 88  
      * <li>From the {@link Class#getClassLoader() callingClass.getClassLoader() }
 89  
      * </ul>
 90  
      *
 91  
      * @param resourceName The name of the resource to load
 92  
      * @param callingClass The Class object of the calling object
 93  
      *
 94  
      * @return A URL pointing to the resource to load or null if the resource is not found
 95  
      */
 96  
     public static URL getResource(final String resourceName, final Class<?> callingClass)
 97  
     {
 98  0
         URL url = AccessController.doPrivileged(new PrivilegedAction<URL>()
 99  0
         {
 100  
             public URL run()
 101  
             {
 102  0
                 final ClassLoader cl = Thread.currentThread().getContextClassLoader();
 103  0
                 return cl != null ? cl.getResource(resourceName) : null;
 104  
             }
 105  
         });
 106  
 
 107  0
         if (url == null)
 108  
         {
 109  0
             url = AccessController.doPrivileged(new PrivilegedAction<URL>()
 110  0
             {
 111  
                 public URL run()
 112  
                 {
 113  0
                     return ClassUtils.class.getClassLoader().getResource(resourceName);
 114  
                 }
 115  
             });
 116  
         }
 117  
 
 118  0
         if (url == null)
 119  
         {
 120  0
             url = AccessController.doPrivileged(new PrivilegedAction<URL>()
 121  0
             {
 122  
                 public URL run()
 123  
                 {
 124  0
                     return callingClass.getClassLoader().getResource(resourceName);
 125  
                 }
 126  
             });
 127  
         }
 128  
 
 129  0
         return url;
 130  
     }
 131  
 
 132  
     public static Enumeration<URL> getResources(final String resourceName, final Class<?> callingClass)
 133  
     {
 134  0
         Enumeration<URL> enumeration = AccessController.doPrivileged(new PrivilegedAction<Enumeration<URL>>()
 135  0
         {
 136  
             public Enumeration<URL> run()
 137  
             {
 138  
                 try
 139  
                 {
 140  0
                     final ClassLoader cl = Thread.currentThread().getContextClassLoader();
 141  0
                     return cl != null ? cl.getResources(resourceName) : null;
 142  
                 }
 143  0
                 catch (IOException e)
 144  
                 {
 145  0
                     return null;
 146  
                 }
 147  
             }
 148  
         });
 149  
 
 150  0
         if (enumeration == null)
 151  
         {
 152  0
             enumeration = AccessController.doPrivileged(new PrivilegedAction<Enumeration<URL>>()
 153  0
             {
 154  
                 public Enumeration<URL> run()
 155  
                 {
 156  
                     try
 157  
                     {
 158  0
                         return ClassUtils.class.getClassLoader().getResources(resourceName);
 159  
                     }
 160  0
                     catch (IOException e)
 161  
                     {
 162  0
                         return null;
 163  
                     }
 164  
                 }
 165  
             });
 166  
         }
 167  
 
 168  0
         if (enumeration == null)
 169  
         {
 170  0
             enumeration = AccessController.doPrivileged(new PrivilegedAction<Enumeration<URL>>()
 171  0
             {
 172  
                 public Enumeration<URL> run()
 173  
                 {
 174  
                     try
 175  
                     {
 176  0
                         return callingClass.getClassLoader().getResources(resourceName);
 177  
                     }
 178  0
                     catch (IOException e)
 179  
                     {
 180  0
                         return null;
 181  
                     }
 182  
                 }
 183  
             });
 184  
         }
 185  
 
 186  0
         return enumeration;
 187  
     }
 188  
 
 189  
     /**
 190  
      * Load a class with a given name. <p/> It will try to load the class in the
 191  
      * following order:
 192  
      * <ul>
 193  
      * <li>From
 194  
      * {@link Thread#getContextClassLoader() Thread.currentThread().getContextClassLoader()}
 195  
      * <li>Using the basic {@link Class#forName(java.lang.String) }
 196  
      * <li>From
 197  
      * {@link Class#getClassLoader() ClassLoaderUtil.class.getClassLoader()}
 198  
      * <li>From the {@link Class#getClassLoader() callingClass.getClassLoader() }
 199  
      * </ul>
 200  
      *
 201  
      * @param className    The name of the class to load
 202  
      * @param callingClass The Class object of the calling object
 203  
      * @return The Class instance
 204  
      * @throws ClassNotFoundException If the class cannot be found anywhere.
 205  
      */
 206  
     public static Class loadClass(final String className, final Class<?> callingClass) throws ClassNotFoundException
 207  
     {
 208  0
         return loadClass(className, callingClass, Object.class);
 209  
     }
 210  
     /**
 211  
      * Load a class with a given name. <p/> It will try to load the class in the
 212  
      * following order:
 213  
      * <ul>
 214  
      * <li>From
 215  
      * {@link Thread#getContextClassLoader() Thread.currentThread().getContextClassLoader()}
 216  
      * <li>Using the basic {@link Class#forName(java.lang.String) }
 217  
      * <li>From
 218  
      * {@link Class#getClassLoader() ClassLoaderUtil.class.getClassLoader()}
 219  
      * <li>From the {@link Class#getClassLoader() callingClass.getClassLoader() }
 220  
      * </ul>
 221  
      *
 222  
      * @param className    The name of the class to load
 223  
      * @param callingClass The Class object of the calling object
 224  
      * @param type the class type to expect to load
 225  
      * @return The Class instance
 226  
      * @throws ClassNotFoundException If the class cannot be found anywhere.
 227  
      */
 228  
     public static <T extends Class> T loadClass(final String className, final Class<?> callingClass, T type) throws ClassNotFoundException
 229  
     {
 230  0
         if (className.length() <= 8)
 231  
         {
 232  
             // Could be a primitive - likely.
 233  0
             if (primitiveTypeNameMap.containsKey(className))
 234  
             {
 235  0
                 return (T) primitiveTypeNameMap.get(className);
 236  
             }
 237  
         }
 238  
         
 239  0
         Class<?> clazz = AccessController.doPrivileged(new PrivilegedAction<Class<?>>()
 240  0
         {
 241  
             public Class<?> run()
 242  
             {
 243  
                 try
 244  
                 {
 245  0
                     final ClassLoader cl = Thread.currentThread().getContextClassLoader();
 246  0
                     return cl != null ? cl.loadClass(className) : null;
 247  
 
 248  
                 }
 249  0
                 catch (ClassNotFoundException e)
 250  
                 {
 251  0
                     return null;
 252  
                 }
 253  
             }
 254  
         });
 255  
 
 256  0
         if (clazz == null)
 257  
         {
 258  0
             clazz = AccessController.doPrivileged(new PrivilegedAction<Class<?>>()
 259  0
             {
 260  
                 public Class<?> run()
 261  
                 {
 262  
                     try
 263  
                     {
 264  0
                         return Class.forName(className);
 265  
                     }
 266  0
                     catch (ClassNotFoundException e)
 267  
                     {
 268  0
                         return null;
 269  
                     }
 270  
                 }
 271  
             });
 272  
         }
 273  
 
 274  0
         if (clazz == null)
 275  
         {
 276  0
             clazz = AccessController.doPrivileged(new PrivilegedAction<Class<?>>()
 277  0
             {
 278  
                 public Class<?> run()
 279  
                 {
 280  
                     try
 281  
                     {
 282  0
                         return ClassUtils.class.getClassLoader().loadClass(className);
 283  
                     }
 284  0
                     catch (ClassNotFoundException e)
 285  
                     {
 286  0
                         return null;
 287  
                     }
 288  
                 }
 289  
             });
 290  
         }
 291  
 
 292  0
         if (clazz == null)
 293  
         {
 294  0
             clazz = AccessController.doPrivileged(new PrivilegedAction<Class<?>>()
 295  0
             {
 296  
                 public Class<?> run()
 297  
                 {
 298  
                     try
 299  
                     {
 300  0
                         return callingClass.getClassLoader().loadClass(className);
 301  
                     }
 302  0
                     catch (ClassNotFoundException e)
 303  
                     {
 304  0
                         return null;
 305  
                     }
 306  
                 }
 307  
             });
 308  
         }
 309  
 
 310  0
         if (clazz == null)
 311  
         {
 312  0
             throw new ClassNotFoundException(className);
 313  
         }
 314  
 
 315  0
         if(type.isAssignableFrom(clazz))
 316  
         {
 317  0
             return (T)clazz;
 318  
         }
 319  
         else
 320  
         {
 321  0
             throw new IllegalArgumentException(String.format("Loaded class '%s' is not assignable from type '%s'", clazz.getName(), type.getName()));
 322  
         }
 323  
     }
 324  
 
 325  
     /**
 326  
      * Load a class with a given name from the given classloader.
 327  
      *
 328  
      * @param className the name of the class to load
 329  
      * @param classLoader the loader to load it from
 330  
      * @return the instance of the class
 331  
      * @throws ClassNotFoundException if the class is not available in the class loader
 332  
      */
 333  
     public static Class loadClass(final String className, final ClassLoader classLoader)
 334  
             throws ClassNotFoundException
 335  
     {
 336  0
         return classLoader.loadClass(className);
 337  
     }
 338  
 
 339  
 
 340  
     /**
 341  
      * Ensure that the given class is properly initialized when the argument is passed in
 342  
      * as .class literal. This method can never fail unless the bytecode is corrupted or
 343  
      * the VM is otherwise seriously confused.
 344  
      *
 345  
      * @param clazz the Class to be initialized
 346  
      * @return the same class but initialized
 347  
      */
 348  
     public static Class<?> initializeClass(Class<?> clazz)
 349  
     {
 350  
         try
 351  
         {
 352  0
             return getClass(clazz.getName(), true);
 353  
         }
 354  0
         catch (ClassNotFoundException e)
 355  
         {
 356  0
             IllegalStateException ise = new IllegalStateException();
 357  0
             ise.initCause(e);
 358  0
             throw ise;
 359  
         }
 360  
     }
 361  
 
 362  
     public static <T> T instanciateClass(Class<? extends T> clazz, Object... constructorArgs)
 363  
             throws SecurityException, NoSuchMethodException, IllegalArgumentException, InstantiationException,
 364  
             IllegalAccessException, InvocationTargetException
 365  
     {
 366  
         Class<?>[] args;
 367  0
         if (constructorArgs != null)
 368  
         {
 369  0
             args = new Class[constructorArgs.length];
 370  0
             for (int i = 0; i < constructorArgs.length; i++)
 371  
             {
 372  0
                 if (constructorArgs[i] == null)
 373  
                 {
 374  0
                     args[i] = null;
 375  
                 }
 376  
                 else
 377  
                 {
 378  0
                     args[i] = constructorArgs[i].getClass();
 379  
                 }
 380  
             }
 381  
         }
 382  
         else
 383  
         {
 384  0
             args = new Class[0];
 385  
         }
 386  
 
 387  
         // try the arguments as given
 388  
         //Constructor ctor = clazz.getConstructor(args);
 389  0
         Constructor<?> ctor = getConstructor(clazz, args);
 390  
 
 391  0
         if (ctor == null)
 392  
         {
 393  
             // try again but adapt value classes to primitives
 394  0
             ctor = getConstructor(clazz, wrappersToPrimitives(args));
 395  
         }
 396  
 
 397  0
         if (ctor == null)
 398  
         {
 399  0
             StringBuffer argsString = new StringBuffer(100);
 400  0
             for (Class<?> arg : args)
 401  
             {
 402  0
                 argsString.append(arg.getName()).append(", ");
 403  
             }
 404  0
             throw new NoSuchMethodException("could not find constructor on class: " + clazz + ", with matching arg params: "
 405  
                     + argsString);
 406  
         }
 407  
 
 408  0
         return (T)ctor.newInstance(constructorArgs);
 409  
     }
 410  
 
 411  
     public static Object instanciateClass(String name, Object... constructorArgs)
 412  
             throws ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException,
 413  
             InstantiationException, IllegalAccessException, InvocationTargetException
 414  
     {
 415  0
         return instanciateClass(name, constructorArgs, (ClassLoader) null);
 416  
     }
 417  
 
 418  
     public static Object instanciateClass(String name, Object[] constructorArgs, Class<?> callingClass)
 419  
             throws ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException,
 420  
             InstantiationException, IllegalAccessException, InvocationTargetException
 421  
     {
 422  0
         Class<?> clazz = loadClass(name, callingClass);
 423  0
         return instanciateClass(clazz, constructorArgs);
 424  
     }
 425  
 
 426  
     public static Object instanciateClass(String name, Object[] constructorArgs, ClassLoader classLoader)
 427  
             throws ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException,
 428  
             InstantiationException, IllegalAccessException, InvocationTargetException
 429  
     {
 430  
         Class<?> clazz;
 431  0
         if (classLoader != null)
 432  
         {
 433  0
             clazz = loadClass(name, classLoader);
 434  
         }
 435  
         else
 436  
         {
 437  0
             clazz = loadClass(name, ClassUtils.class);
 438  
         }
 439  0
         if (clazz == null)
 440  
         {
 441  0
             throw new ClassNotFoundException(name);
 442  
         }
 443  0
         return instanciateClass(clazz, constructorArgs);
 444  
     }
 445  
 
 446  
     public static Class<?>[] getParameterTypes(Object bean, String methodName)
 447  
     {
 448  0
         if (!methodName.startsWith("set"))
 449  
         {
 450  0
             methodName = "set" + methodName.substring(0, 1).toUpperCase() + methodName.substring(1);
 451  
         }
 452  
 
 453  0
         Method methods[] = bean.getClass().getMethods();
 454  
 
 455  0
         for (int i = 0; i < methods.length; i++)
 456  
         {
 457  0
             if (methods[i].getName().equals(methodName))
 458  
             {
 459  0
                 return methods[i].getParameterTypes();
 460  
             }
 461  
         }
 462  
 
 463  0
         return new Class[]{};
 464  
     }
 465  
 
 466  
     /**
 467  
      * Returns a matching method for the given name and parameters on the given class
 468  
      * If the parameterTypes arguments is null it will return the first matching
 469  
      * method on the class.
 470  
      *
 471  
      * @param clazz          the class to find the method on
 472  
      * @param name           the method name to find
 473  
      * @param parameterTypes an array of argument types or null
 474  
      * @return the Method object or null if none was found
 475  
      */
 476  
     public static Method getMethod(Class<?> clazz, String name, Class<?>[] parameterTypes)
 477  
     {
 478  0
         return getMethod(clazz, name, parameterTypes, false);
 479  
     }
 480  
 
 481  
     public static Method getMethod(Class clazz, String name, Class[] parameterTypes, boolean acceptNulls)
 482  
     {
 483  0
         Method[] methods = clazz.getMethods();
 484  0
         for (int i = 0; i < methods.length; i++)
 485  
         {
 486  0
             if (methods[i].getName().equals(name))
 487  
             {
 488  0
                 if (parameterTypes == null)
 489  
                 {
 490  0
                     return methods[i];
 491  
                 }
 492  0
                 else if (compare(methods[i].getParameterTypes(), parameterTypes, true, acceptNulls))
 493  
                 {
 494  0
                     return methods[i];
 495  
                 }
 496  
             }
 497  
         }
 498  0
         return null;
 499  
     }
 500  
 
 501  
     public static Constructor getConstructor(Class clazz, Class[] paramTypes)
 502  
     {
 503  0
         return getConstructor(clazz, paramTypes, false);
 504  
     }
 505  
     
 506  
     /**
 507  
      *  Returns available constructor in the target class that as the parameters specified.
 508  
      *
 509  
      * @param clazz the class to search
 510  
      * @param paramTypes the param types to match against
 511  
      * @param exactMatch should exact types be used (i.e. equals rather than isAssignableFrom.)
 512  
      * @return The matching constructor or null if no matching constructor is found
 513  
      */
 514  
     public static Constructor getConstructor(Class clazz, Class[] paramTypes, boolean exactMatch)
 515  
     {
 516  0
         Constructor[] ctors = clazz.getConstructors();
 517  0
         for (int i = 0; i < ctors.length; i++)
 518  
         {
 519  0
             Class[] types = ctors[i].getParameterTypes();
 520  0
             if (types.length == paramTypes.length)
 521  
             {
 522  0
                 int matchCount = 0;
 523  0
                 for (int x = 0; x < types.length; x++)
 524  
                 {
 525  0
                     if (paramTypes[x] == null)
 526  
                     {
 527  0
                         matchCount++;
 528  
                     }
 529  
                     else
 530  
                     {
 531  0
                         if (exactMatch)
 532  
                         {
 533  0
                             if (paramTypes[x].equals(types[x]) || types[x].equals(paramTypes[x]))
 534  
                             {
 535  0
                                 matchCount++;
 536  
                             }
 537  
                         }
 538  
                         else
 539  
                         {
 540  0
                             if (paramTypes[x].isAssignableFrom(types[x])
 541  
                                 || types[x].isAssignableFrom(paramTypes[x]))
 542  
                             {
 543  0
                                 matchCount++;
 544  
                             }
 545  
                         }
 546  
                     }
 547  
                 }
 548  0
                 if (matchCount == types.length)
 549  
                 {
 550  0
                     return ctors[i];
 551  
                 }
 552  
             }
 553  
         }
 554  0
         return null;
 555  
     }
 556  
 
 557  
     /**
 558  
      * A helper method that will find all matching methods on a class with the given
 559  
      * parameter type
 560  
      *
 561  
      * @param implementation     the class to build methods on
 562  
      * @param parameterTypes     the argument param types to look for
 563  
      * @param voidOk             whether void methods shouldbe included in the found list
 564  
      * @param matchOnObject      determines whether parameters of Object type are matched
 565  
      *                           when they are of Object.class type
 566  
      * @param ignoredMethodNames a Set of method names to ignore. Often 'equals' is
 567  
      *                           not a desired match. This argument can be null.
 568  
      * @return a List of methods on the class that match the criteria. If there are
 569  
      *         none, an empty list is returned
 570  
      */
 571  
     public static List<Method> getSatisfiableMethods(Class<?> implementation,
 572  
                                              Class<?>[] parameterTypes,
 573  
                                              boolean voidOk,
 574  
                                              boolean matchOnObject,
 575  
                                              Set<String> ignoredMethodNames)
 576  
     {
 577  0
         return getSatisfiableMethods(implementation, parameterTypes, voidOk, matchOnObject, ignoredMethodNames, null);
 578  
     }
 579  
 
 580  
     /**
 581  
      * A helper method that will find all matching methods on a class with the given
 582  
      * parameter type
 583  
      *
 584  
      * @param implementation     the class to build methods on
 585  
      * @param parameterTypes     the argument param types to look for
 586  
      * @param voidOk             whether void methods shouldbe included in the found list
 587  
      * @param matchOnObject      determines whether parameters of Object type are matched
 588  
      *                           when they are of Object.class type
 589  
      * @param ignoredMethodNames a Set of method names to ignore. Often 'equals' is
 590  
      *                           not a desired match. This argument can be null.
 591  
      * @param filter             Wildcard expression filter that allows methods to be matched using wildcards i.e. 'get*'
 592  
      * @return a List of methods on the class that match the criteria. If there are
 593  
      *         none, an empty list is returned
 594  
      */
 595  
     public static List<Method> getSatisfiableMethods(Class<?> implementation,
 596  
                                              Class<?>[] parameterTypes,
 597  
                                              boolean voidOk,
 598  
                                              boolean matchOnObject,
 599  
                                              Collection<String> ignoredMethodNames,
 600  
                                              WildcardFilter filter)
 601  
     {
 602  0
         List<Method> result = new ArrayList<Method>();
 603  
 
 604  0
         if (ignoredMethodNames == null)
 605  
         {
 606  0
             ignoredMethodNames = Collections.emptySet();
 607  
         }
 608  
 
 609  0
         Method[] methods = implementation.getMethods();
 610  0
         for (int i = 0; i < methods.length; i++)
 611  
         {
 612  0
             Method method = methods[i];
 613  
             //supporting wildcards
 614  0
             if (filter != null && filter.accept(method.getName()))
 615  
             {
 616  0
                 continue;
 617  
             }
 618  0
             Class<?>[] methodParams = method.getParameterTypes();
 619  
 
 620  0
             if (compare(methodParams, parameterTypes, matchOnObject))
 621  
             {
 622  0
                 if (!ignoredMethodNames.contains(method.getName()))
 623  
                 {
 624  0
                     String returnType = method.getReturnType().getName();
 625  0
                     if ((returnType.equals("void") && voidOk) || !returnType.equals("void"))
 626  
                     {
 627  0
                         result.add(method);
 628  
                     }
 629  
                 }
 630  
             }
 631  
         }
 632  
 
 633  0
         return result;
 634  
     }
 635  
 
 636  
     /**
 637  
      * Match all method son a class with a defined return type
 638  
      * @param implementation the class to search
 639  
      * @param returnType the return type to match
 640  
      * @param matchOnObject whether {@link Object} methods should be matched
 641  
      * @param ignoredMethodNames a set of method names to ignore
 642  
      * @return the list of methods that matched the return type and criteria. If none are found an empty result is returned
 643  
      */
 644  
     public static List<Method> getSatisfiableMethodsWithReturnType(Class implementation,
 645  
                                                            Class returnType,
 646  
                                                            boolean matchOnObject,
 647  
                                                            Set<String> ignoredMethodNames)
 648  
     {
 649  0
         List<Method> result = new ArrayList<Method>();
 650  
 
 651  0
         if (ignoredMethodNames == null)
 652  
         {
 653  0
             ignoredMethodNames = Collections.emptySet();
 654  
         }
 655  
 
 656  0
         Method[] methods = implementation.getMethods();
 657  0
         for (int i = 0; i < methods.length; i++)
 658  
         {
 659  0
             Method method = methods[i];
 660  0
             Class returns = method.getReturnType();
 661  
 
 662  0
             if (compare(new Class[]{returns}, new Class[]{returnType}, matchOnObject))
 663  
             {
 664  0
                 if (!ignoredMethodNames.contains(method.getName()))
 665  
                 {
 666  0
                     result.add(method);
 667  
                 }
 668  
             }
 669  
         }
 670  
 
 671  0
         return result;
 672  
     }
 673  
 
 674  
     /**
 675  
      * Can be used by serice endpoints to select which service to use based on what's
 676  
      * loaded on the classpath
 677  
      *
 678  
      * @param className    The class name to look for
 679  
      * @param currentClass the calling class
 680  
      * @return true if the class is on the path
 681  
      */
 682  
     public static boolean isClassOnPath(String className, Class currentClass)
 683  
     {
 684  
         try
 685  
         {
 686  0
             return (loadClass(className, currentClass) != null);
 687  
         }
 688  0
         catch (ClassNotFoundException e)
 689  
         {
 690  0
             return false;
 691  
         }
 692  
     }
 693  
 
 694  
     /**
 695  
      * Used for creating an array of class types for an array or single object
 696  
      *
 697  
      * @param object single object or array. If this parameter is null or a zero length
 698  
      *               array then {@link #NO_ARGS_TYPE} is returned
 699  
      * @return an array of class types for the object
 700  
      */
 701  
     public static Class<?>[] getClassTypes(Object object)
 702  
     {
 703  0
         if (object == null)
 704  
         {
 705  0
             return NO_ARGS_TYPE;
 706  
         }
 707  
 
 708  
         Class<?>[] types;
 709  
 
 710  0
         if (object instanceof Object[])
 711  
         {
 712  0
             Object[] objects = (Object[]) object;
 713  0
             if (objects.length == 0)
 714  
             {
 715  0
                 return NO_ARGS_TYPE;
 716  
             }
 717  0
             types = new Class[objects.length];
 718  0
             for (int i = 0; i < objects.length; i++)
 719  
             {
 720  0
                 Object o = objects[i];
 721  0
                 if (o != null)
 722  
                 {
 723  0
                     types[i] = o.getClass();
 724  
                 }
 725  
             }
 726  0
         }
 727  
         else
 728  
         {
 729  0
             types = new Class[]{object.getClass()};
 730  
         }
 731  
 
 732  0
         return types;
 733  
     }
 734  
 
 735  
     public static String getClassName(Class clazz)
 736  
     {
 737  0
         if (clazz == null)
 738  
         {
 739  0
             return null;
 740  
         }
 741  0
         String name = clazz.getName();
 742  0
         return name.substring(name.lastIndexOf(".") + 1);
 743  
     }
 744  
 
 745  
     public static boolean compare(Class[] c1, Class[] c2, boolean matchOnObject)
 746  
     {
 747  0
         return compare(c1, c2, matchOnObject, false);
 748  
     }
 749  
 
 750  
     /**
 751  
      * Returns true if the types from array c2 are assignable to the types from c1
 752  
      * and the arrays are the same size. If matchOnObject argument is true and there
 753  
      * is a parameter of type Object in c1 then the method returns false. If
 754  
      * acceptNulls argument is true, null values are accepted in c2.
 755  
      * 
 756  
      * @param c1 parameter types array
 757  
      * @param c2 parameter types array
 758  
      * @param matchOnObject return false if there is a parameter of type Object in c1
 759  
      * @param acceptNulls allows null parameter types in c2
 760  
      * @return true if arrays are the same size and the types assignable from c2 to
 761  
      *         c1
 762  
      */
 763  
     public static boolean compare(Class[] c1, Class[] c2, boolean matchOnObject, boolean acceptNulls)
 764  
     {
 765  0
         if (c1.length != c2.length)
 766  
         {
 767  0
             return false;
 768  
         }
 769  0
         for (int i = 0; i < c1.length; i++)
 770  
         {
 771  0
             if (!acceptNulls)
 772  
             {
 773  0
                 if ((c1[i] == null) || (c2[i] == null))
 774  
                 {
 775  0
                     return false;
 776  
                 }
 777  
             } 
 778  
             else 
 779  
             {
 780  0
                 if (c1[i] == null)
 781  
                 {
 782  0
                     return false;
 783  
                 }
 784  0
                 if ((c2[i] == null) && (c1[i].isPrimitive()))
 785  
                 {
 786  0
                     return false;
 787  
                 }
 788  0
                 if (c2[i] == null)
 789  
                 {
 790  0
                     return true;
 791  
                 }
 792  
             }
 793  0
             if (c1[i].equals(Object.class) && !matchOnObject)
 794  
             {
 795  0
                 return false;
 796  
             }
 797  0
             if (!c1[i].isAssignableFrom(c2[i]))
 798  
             {
 799  0
                 return false;
 800  
             }
 801  
         }
 802  0
         return true;
 803  
     }
 804  
 
 805  
     public static Class wrapperToPrimitive(Class wrapper)
 806  
     {
 807  0
         return (Class) MapUtils.getObject(wrapperToPrimitiveMap, wrapper, wrapper);
 808  
     }
 809  
 
 810  
     public static Class[] wrappersToPrimitives(Class[] wrappers)
 811  
     {
 812  0
         if (wrappers == null)
 813  
         {
 814  0
             return null;
 815  
         }
 816  
 
 817  0
         if (wrappers.length == 0)
 818  
         {
 819  0
             return wrappers;
 820  
         }
 821  
 
 822  0
         Class[] primitives = new Class[wrappers.length];
 823  
 
 824  0
         for (int i = 0; i < wrappers.length; i++)
 825  
         {
 826  0
             primitives[i] = (Class) MapUtils.getObject(wrapperToPrimitiveMap, wrappers[i], wrappers[i]);
 827  
         }
 828  
 
 829  0
         return primitives;
 830  
     }
 831  
 
 832  
     /**
 833  
      * Provide a simple-to-understand class name (with access to only Java 1.4 API).
 834  
      *
 835  
      * @param clazz The class whose name we will generate
 836  
      * @return A readable name for the class
 837  
      */
 838  
     public static String getSimpleName(Class clazz)
 839  
     {
 840  0
         if (null == clazz)
 841  
         {
 842  0
             return "null";
 843  
         }
 844  
         else
 845  
         {
 846  0
             return classNameHelper(new BufferedReader(new CharArrayReader(clazz.getName().toCharArray())));
 847  
         }
 848  
     }
 849  
 
 850  
     private static String classNameHelper(Reader encodedName)
 851  
     {
 852  
         // I did consider separating this data from the code, but I could not find a
 853  
         // solution that was as clear to read, or clearly motivated (these data are not
 854  
         // used elsewhere).
 855  
 
 856  
         try
 857  
         {
 858  0
             encodedName.mark(1);
 859  0
             switch (encodedName.read())
 860  
             {
 861  
                 case -1:
 862  0
                     return "null";
 863  
                 case 'Z':
 864  0
                     return "boolean";
 865  
                 case 'B':
 866  0
                     return "byte";
 867  
                 case 'C':
 868  0
                     return "char";
 869  
                 case 'D':
 870  0
                     return "double";
 871  
                 case 'F':
 872  0
                     return "float";
 873  
                 case 'I':
 874  0
                     return "int";
 875  
                 case 'J':
 876  0
                     return "long";
 877  
                 case 'S':
 878  0
                     return "short";
 879  
                 case '[':
 880  0
                     return classNameHelper(encodedName) + "[]";
 881  
                 case 'L':
 882  0
                     return shorten(new BufferedReader(encodedName).readLine());
 883  
                 default:
 884  0
                     encodedName.reset();
 885  0
                     return shorten(new BufferedReader(encodedName).readLine());
 886  
             }
 887  
         }
 888  0
         catch (IOException e)
 889  
         {
 890  0
             return "unknown type: " + e.getMessage();
 891  
         }
 892  
     }
 893  
 
 894  
     /**
 895  
      * @param clazz A class name (with possible package and trailing semicolon)
 896  
      * @return The short name for the class
 897  
      */
 898  
     private static String shorten(String clazz)
 899  
     {
 900  0
         if (null != clazz && clazz.endsWith(";"))
 901  
         {
 902  0
             clazz = clazz.substring(0, clazz.length() - 1);
 903  
         }
 904  0
         if (null != clazz && clazz.lastIndexOf(".") > -1)
 905  
         {
 906  0
             clazz = clazz.substring(clazz.lastIndexOf(".") + 1, clazz.length());
 907  
         }
 908  0
         return clazz;
 909  
     }
 910  
 
 911  
     /**
 912  
      * Simple helper for writing object equalities.
 913  
      *
 914  
      * TODO Is there a better place for this?
 915  
      * @param a object to compare
 916  
      * @param b object to be compared to
 917  
      * @return true if the objects are equal (value or reference), false otherwise
 918  
      */
 919  
     public static boolean equal(Object a, Object b)
 920  
     {
 921  0
         if (null == a)
 922  
         {
 923  0
             return null == b;
 924  
         }
 925  
         else
 926  
         {
 927  0
             return null != b && a.equals(b);
 928  
         }
 929  
     }
 930  
 
 931  
     public static int hash(Object[] state)
 932  
     {
 933  0
         int hash = 0;
 934  0
         for (int i = 0; i < state.length; ++i)
 935  
         {
 936  0
             hash = hash * 31 + (null == state[i] ? 0 : state[i].hashCode());
 937  
         }
 938  0
         return hash;
 939  
     }
 940  
 
 941  
     public static void addLibrariesToClasspath(List urls) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException
 942  
     {
 943  0
         ClassLoader sys = ClassLoader.getSystemClassLoader();
 944  0
         if (!(sys instanceof URLClassLoader))
 945  
         {
 946  0
             throw new IllegalArgumentException(
 947  
                     "PANIC: Mule has been started with an unsupported classloader: " + sys.getClass().getName()
 948  
                             + ". " + "Please report this error to user<at>mule<dot>codehaus<dot>org");
 949  
         }
 950  
 
 951  
         // system classloader is in this case the one that launched the application,
 952  
         // which is usually something like a JDK-vendor proprietary AppClassLoader
 953  0
         URLClassLoader sysCl = (URLClassLoader) sys;
 954  
 
 955  
         /*
 956  
         * IMPORTANT NOTE: The more 'natural' way would be to create a custom
 957  
         * URLClassLoader and configure it, but then there's a chicken-and-egg
 958  
         * problem, as all classes MuleBootstrap depends on would have been loaded by
 959  
         * a parent classloader, and not ours. There's no straightforward way to
 960  
         * change this, and is documented in a Sun's classloader guide. The solution
 961  
         * would've involved overriding the ClassLoader.findClass() method and
 962  
         * modifying the semantics to be child-first, but that way we are calling for
 963  
         * trouble. Hacking the primordial classloader is a bit brutal, but works
 964  
         * perfectly in case of running from the command-line as a standalone app.
 965  
         * All Mule embedding options then delegate the classpath config to the
 966  
         * embedder (a developer embedding Mule in the app), thus classloaders are
 967  
         * not modified in those scenarios.
 968  
         */
 969  
 
 970  
         // get a Method ref from the normal class, but invoke on a proprietary parent
 971  
         // object,
 972  
         // as this method is usually protected in those classloaders
 973  0
         Class refClass = URLClassLoader.class;
 974  0
         Method methodAddUrl = refClass.getDeclaredMethod("addURL", new Class[]{URL.class});
 975  0
         methodAddUrl.setAccessible(true);
 976  0
         for (Iterator it = urls.iterator(); it.hasNext();)
 977  
         {
 978  0
             URL url = (URL) it.next();
 979  0
             methodAddUrl.invoke(sysCl, url);
 980  0
         }
 981  0
     }
 982  
 
 983  
     // this is a shorter version of the snippet from:
 984  
     // http://www.davidflanagan.com/blog/2005_06.html#000060
 985  
     // (see comments; DF's "manual" version works fine too)
 986  
     public static URL getClassPathRoot(Class clazz)
 987  
     {
 988  0
         CodeSource cs = clazz.getProtectionDomain().getCodeSource();
 989  0
         return (cs != null ? cs.getLocation() : null);
 990  
     }
 991  
 }