// Path: engine/src/main/java/com/impossibl/stencil/engine/ExecutionException.java
// public class ExecutionException extends RuntimeException {
// 
//   private static final long serialVersionUID = 376006343757200461L;
//   
//   ExecutionLocation location;
// 
//   public ExecutionException() {
//   }
// 
//   public ExecutionException(String message, Throwable cause, ExecutionLocation location) {
//     super(location + ": " + message, cause);
//     this.location = location;
//   }
//   
//   public ExecutionException(String message, ExecutionLocation location) {
//     super(location + ": " + message);
//     this.location = location;
//   }
// 
//   public ExecutionException(Throwable cause, ExecutionLocation location) {
//     super(cause);
//     this.location = location;
//   }
// 
//   public ExecutionLocation getLocation() {
//     return location;
//   }
// 
//   public void setLocation(ExecutionLocation location) {
//     this.location = location;
//   }
// 
// }
// 
// Path: engine/src/main/java/com/impossibl/stencil/engine/InvocationException.java
// public class InvocationException extends ExecutionException {
// 
//   private static final long serialVersionUID = -5527033329538312329L;
// 
//   public InvocationException() {
// 	}
// 
//   public InvocationException(String message, Throwable cause, ExecutionLocation location) {
//     super(message, cause, location);
//   }
// 
//   public InvocationException(String message, ExecutionLocation location) {
//     super(message, location);
//   }
// 
// }


import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
import com.impossibl.stencil.api.Named;
import com.impossibl.stencil.engine.ExecutionException;
import com.impossibl.stencil.engine.InvocationException;
import com.thoughtworks.paranamer.AnnotationParanamer;
import com.thoughtworks.paranamer.CachingParanamer;
import com.thoughtworks.paranamer.Paranamer;
package com.impossibl.stencil.api.impl;



/**
 * Utility class for handling annotated Callable's and Preparable's
 * 
 * @author kdubb
 * @see com.impossibl.stencil.api.Callable
 * @see com.impossibl.stencil.api.Preparable
 *
 */
public class AnnotatedExtensions {

  private static Paranamer paranamer = new CachingParanamer(new AnnotationParanamer() {

    @Override
    protected String getNamedValue(Annotation ann) {
      return ((Named)ann).value();
    }

    @Override
    protected boolean isNamed(Annotation ann) {
      return Named.class.isInstance(ann);
    }
    
  });

  /**
   * Retrieves the Named annotated parameter names from the given method
   * 
   * @param method Method to retrieve annotated parameter names for
   * @return Names of parameters annotated with Named
   * @see com.impossibl.stencil.api.Named
   */
  public static String[] getParameterNames(Method method) {
    return paranamer.lookupParameterNames(method);
  }
  
  /**
   * Finds a named declared method on the given class.
   * 
   * @param name Name of declared method to retrieve
   * @param cls Class to retrieve method from
   * @return Named method on class
   */
  public static Method findMethod(String name, Class<?> cls) {
    
    for(Method method : cls.getDeclaredMethods()) {
      if(method.getName().equals(name)) {
        return method;
      }
    }
    
// Path: engine/src/main/java/com/impossibl/stencil/engine/ExecutionException.java
// public class ExecutionException extends RuntimeException {
// 
//   private static final long serialVersionUID = 376006343757200461L;
//   
//   ExecutionLocation location;
// 
//   public ExecutionException() {
//   }
// 
//   public ExecutionException(String message, Throwable cause, ExecutionLocation location) {
//     super(location + ": " + message, cause);
//     this.location = location;
//   }
//   
//   public ExecutionException(String message, ExecutionLocation location) {
//     super(location + ": " + message);
//     this.location = location;
//   }
// 
//   public ExecutionException(Throwable cause, ExecutionLocation location) {
//     super(cause);
//     this.location = location;
//   }
// 
//   public ExecutionLocation getLocation() {
//     return location;
//   }
// 
//   public void setLocation(ExecutionLocation location) {
//     this.location = location;
//   }
// 
// }
// 
// Path: engine/src/main/java/com/impossibl/stencil/engine/InvocationException.java
// public class InvocationException extends ExecutionException {
// 
//   private static final long serialVersionUID = -5527033329538312329L;
// 
//   public InvocationException() {
// 	}
// 
//   public InvocationException(String message, Throwable cause, ExecutionLocation location) {
//     super(message, cause, location);
//   }
// 
//   public InvocationException(String message, ExecutionLocation location) {
//     super(message, location);
//   }
// 
// }


// Path: engine/src/main/java/com/impossibl/stencil/api/impl/AnnotatedExtensions.java
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
import com.impossibl.stencil.api.Named;
import com.impossibl.stencil.engine.ExecutionException;
import com.impossibl.stencil.engine.InvocationException;
import com.thoughtworks.paranamer.AnnotationParanamer;
import com.thoughtworks.paranamer.CachingParanamer;
import com.thoughtworks.paranamer.Paranamer;

package com.impossibl.stencil.api.impl;



/**
 * Utility class for handling annotated Callable's and Preparable's
 * 
 * @author kdubb
 * @see com.impossibl.stencil.api.Callable
 * @see com.impossibl.stencil.api.Preparable
 *
 */
public class AnnotatedExtensions {

  private static Paranamer paranamer = new CachingParanamer(new AnnotationParanamer() {

    @Override
    protected String getNamedValue(Annotation ann) {
      return ((Named)ann).value();
    }

    @Override
    protected boolean isNamed(Annotation ann) {
      return Named.class.isInstance(ann);
    }
    
  });

  /**
   * Retrieves the Named annotated parameter names from the given method
   * 
   * @param method Method to retrieve annotated parameter names for
   * @return Names of parameters annotated with Named
   * @see com.impossibl.stencil.api.Named
   */
  public static String[] getParameterNames(Method method) {
    return paranamer.lookupParameterNames(method);
  }
  
  /**
   * Finds a named declared method on the given class.
   * 
   * @param name Name of declared method to retrieve
   * @param cls Class to retrieve method from
   * @return Named method on class
   */
  public static Method findMethod(String name, Class<?> cls) {
    
    for(Method method : cls.getDeclaredMethods()) {
      if(method.getName().equals(name)) {
        return method;
      }
    }
    
    throw new ExecutionException("invalid auto-function: no '" + name + "' method declared", null);