/**
 * GUI Commands
 * Copyright 2004 Andrew Pietsch
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * $Id: ReflectionCommand.java,v 1.3 2004/12/12 05:29:25 pietschy Exp $
 */
package org.pietschy.command;

import java.lang.reflect.Method;


/**
 * The ReflectionCommand invokes a target method using reflection.
 * @version $Revision: 1.3 $
 * @author andrewp
 */
public class
ReflectionCommand
extends ActionCommand
{
   private static final String _ID_ = "$Id: ReflectionCommand.java,v 1.3 2004/12/12 05:29:25 pietschy Exp $";

   private Object instance;
   private Method method;

   /**
    * Creates a new reflection command that invokes a static no arg method.  This constructor uses
    * it's own classloader that loaded the target class.
    * @param commandId the id of the command.
    * @param className the class on which the static method resides
    * @param methodName the name of the no arg static method.
    * @throws NoSuchMethodException if the method doesn't exist
    * @throws NullPointerException if either the instance or methodName is null.
    */
   public ReflectionCommand(String commandId, String className, String methodName)
   throws NoSuchMethodException, ClassNotFoundException
   {
      super(commandId);

      if (className == null)
         throw new NullPointerException("className is null");

      if (methodName == null)
         throw new NullPointerException("methodName is null");

      initialize(null, getClass().getClassLoader().loadClass(className), methodName, null);
   }

   /**
    * Creates a new reflection command that invokess a static no arg method.
    * @param commandId the id of the command.
    * @param clazz the class on which the static method resides
    * @param methodName the name of the no arg static method.
    * @throws NoSuchMethodException if the method doesn't exist
    * @throws NullPointerException if either the instance or methodName is null.
    */
   public ReflectionCommand(String commandId, Class clazz, String methodName)
   throws NoSuchMethodException
   {
      super(commandId);

      if (clazz == null)
         throw new NullPointerException("clazz is null");

      if (methodName == null)
         throw new NullPointerException("methodName is null");

      initialize(null, clazz, methodName, null);
   }

   /**
    * Creates a new reflection command that invokes a static class method with arguments.
    * @param commandId the id of the command.
    * @param clazz the class on which the static method resides.
    * @param methodName the method name.
    * @param methodArgs the arguments of the method.  This may be null if the argument takes
    * no methods.  If arguments are specified, the {@link #getInvocationArgs} method must be
    * implemented to provide the arguments to the method invocation.
    * @throws NoSuchMethodException if the method doesn't exist
    * @throws NullPointerException if either the instance or methodName is null.
    */
   public ReflectionCommand(String commandId, Class clazz, String methodName, Class[] methodArgs)
   throws NoSuchMethodException
   {
      super(commandId);

      if (clazz == null)
         throw new NullPointerException("clazz is null");

      if (methodName == null)
         throw new NullPointerException("methodName is null");

      initialize(null, clazz, methodName, methodArgs);
   }

   /**
    * Creates a new reflection command that invokes a non static method on the specified object.
    * @param commandId the id of the command
    * @param instance that target instance on which the method will be invoked.
    * @param methodName the name of the method to invoke.
    * @throws NoSuchMethodException if the method doesn't exist
    * @throws NullPointerException if either the instance or methodName is null.
    */
   public ReflectionCommand(String commandId, Object instance, String methodName)
   throws NoSuchMethodException
   {
      super(commandId);

      if (instance == null)
         throw new NullPointerException("instance is null");

      if (methodName == null)
         throw new NullPointerException("methodName is null");

      initialize(instance, instance.getClass(), methodName, null);
   }

   /**
    *
    * @param commandId
    * @param instance
    * @param methodName
    * @param methodArgs the arguments of the method.  This may be null if the argument takes
    * no methods.  If arguments are specified, the {@link #getInvocationArgs} method must be
    * implemented to provide the arguments to the method invocation.
    * @throws NoSuchMethodException if the method doesn't exist
    * @throws NullPointerException if either the instance or methodName is null.
    */
   public ReflectionCommand(String commandId, Object instance, String methodName, Class[] methodArgs)
   throws NoSuchMethodException
   {
      super(commandId);

      if (instance == null)
         throw new NullPointerException("instance is null");

      if (methodName == null)
         throw new NullPointerException("methodName is null");

      initialize(instance, instance.getClass(), methodName, methodArgs);
   }

   private void
   initialize(Object instance, Class clazz, String methodName, Class[] methodArgs)
   throws NoSuchMethodException
   {
      this.instance = instance;
      this.method = clazz.getMethod(methodName, methodArgs);
   }

   protected final void
   handleExecute()
   {
      try
      {
         method.invoke(instance, getInvocationArgs());
      }
      catch (Exception e)
      {
         handleInvocationException(e);
      }
   }

   /**
    * Gets any arguments required by the delegate.  The default implementation returns
    * <tt>null</tt>, subclass should override as required.
    * @return the arguments required for the method delegate.  Returns <tt>null</tt> by default.
    */
   protected Object[]
   getInvocationArgs()
   {
      return null;
   }

   /**
    * Called to handle any exceptions that occur during the invocation of the delegate method.
    * @param e the exception that occured while calling method.invoke(..)
    */
   protected void
   handleInvocationException(Exception e)
   {
      e.printStackTrace();
   }

}
