// Updates: 2004.08.16


import java.io.*;
import java.net.*;
import java.lang.reflect.*;


/**
 * <b>Invoker</b> lets you invoke protected and private methods in any object.
 * Examples:<br>
 * <pre>
public class TestInvoker {
  
  public TestInvoker() {
    Invoker.addPath("C:/AADev/examples/");
    VeryPrivate vp = new VeryPrivate();
    try {
      Invoker.invoke(VeryPrivate.class, vp, "test1", new Object[]{});
      Invoker.invoke(VeryPrivate.class, vp, "test2", new Object[]{"Hello!"});
      Invoker.invoke(VeryPrivate.class, vp, "test3", new Class[]{Integer.TYPE}, new Object[]{new Integer(555)});
      Invoker.invoke(VeryPrivate.class, vp, "test4", new Class[]{String.class, Integer.TYPE}, new Object[]{"Hello again!", new Integer(555)});
    }
    catch (Exception e) {
      System.out.println("Problem: " + e);
    }    
  }
  
  public static void main(String[] args) {
    new TestInvoker();
  }
}


class VeryPrivate {

  private void test1() {
    System.out.println("Test1: no parameters");
  }
    
  private void test2(String s) {
    System.out.println("Test2: a String: " + s);
  }  
     
  private void test3(int i) {
    System.out.println("Test3: an integer: " + i);
  }
        
  private void test4(String s, int i) {
    System.out.println("Test4: a String: " + s + ", and an Integer: " + i);
  }
}
 *</pre> 
 * @author Michel Deriaz
 */
public class Invoker {


  private Invoker() {}


  /**
   * Invokes a method containing no primitive types. If the method has primitive
   * types, see the {@link #invoke(Class, Object, String, Class[], Object[])
   * invoke(Class, Object, String, Class[], Object[])} method.
   * @param className the class of the object, for example 
   * <code>URLClassLoader.class</code>
   * @param obj the object containing the method to invoke
   * @param method the name of the method to invoke, for example
   * <code>"addURL"</code>
   * @param param the parameters, for example <code>new Object[]{url}</code>
   * @throws Exception the following exceptions can be thrown from this method: 
   * <code>NoSuchMethodException</code>,
   * <code>NullPointerException</code>,
   * <code>SecurityException</code>,
   * <code>IllegalAccessException</code>,
   * <code>IllegalArgumentException</code>,
   * <code>InvocationTargetException</code>,
   * <code>ExceptionInInitializerError</code>.
   * @see #invoke(Class, Object, String, Class[], Object[])
   */
  public static void invoke(Class className, Object obj, String method, Object[] param) throws Exception {
    Class[] paramClass = new Class[param.length];
    for (int i = 0; i < param.length; i++) {
      paramClass[i] = param[i].getClass();
    }
    invoke(className, obj, method, paramClass, param);
  }


  /**
   * Invokes a method containing primitive types. If the method has no primitive
   * types, see the {@link #invoke(Class, Object, String, Object[])
   * invoke(Class, Object, String, Object[])} method.
   * @param className the class of the object, for example 
   * <code>MyProgram.class</code>
   * @param obj the object containing the method to invoke
   * @param method the name of the method to invoke, for example
   * <code>"testMethod"</code>
   * @param paramClass the classes of the parameters, for exemple
   * <code>new Class[]{Integer.TYPE}</code>
   * @param param the parameters, for example <code>new Object[]{new
   * Integer(555)}</code>
   * @throws Exception the following exceptions can be thrown from this method: 
   * <code>NoSuchMethodException</code>,
   * <code>NullPointerException</code>,
   * <code>SecurityException</code>,
   * <code>IllegalAccessException</code>,
   * <code>IllegalArgumentException</code>,
   * <code>InvocationTargetException</code>,
   * <code>ExceptionInInitializerError</code>.
   * @see #invoke(Class, Object, String, Object[])
   */
  public static void invoke(Class className, Object obj, String method, Class[] paramClass, Object[] param) throws Exception {
    Method m = className.getDeclaredMethod(method, paramClass);
    m.setAccessible(true);
    m.invoke(obj, param);
  }


  /**
   * Invokes the protected <code>addURL</code> method from the
   * <code>URLClassLoader</code> class, in order to bypass the fact that it is
   * not possible to modify the classpath during runtime.
   * @param path the path to add
   */
  public static void addPath(String path) {
    if (path == null) return;
    try {
      URL url = new File(path).toURL();
      URLClassLoader loader = (URLClassLoader)ClassLoader.getSystemClassLoader();
      invoke(URLClassLoader.class, loader, "addURL", new Object[]{url});
    }
    catch (Exception e) {}
  }
}