/*
 * JBoss, the OpenSource J2EE webOS
 *
 * Distributable under LGPL license.
 * See terms of license at gnu.org.
 */
package org.jboss.verifier.strategy;

// $Id: AbstractEJB2xVerifier.java,v 1.1.2.1 2005/02/08 09:15:48 tdiesler Exp $

import org.jboss.metadata.EntityMetaData;
import org.jboss.metadata.QueryMetaData;
import org.jboss.util.Classes;

import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

/**
 * Abstract EJB 2.x bean verifier.
 *
 * @author Thomas.Diesler@jboss.org
 * @since  08-Feb-2005
 */

public abstract class AbstractEJB2xVerifier extends AbstractVerifier
{
   protected EJBVerifier11 cmp1XVerifier;

   // The classes for an EJB
   protected Class bean;
   protected Class home;
   protected Class remote;
   protected Class localHome;
   protected Class local;
   protected Class serviceEndpointInterface;

   /*
    * Constructor
    */
   public AbstractEJB2xVerifier(VerificationContext context)
   {
      super(context);
   }

   /**
    * Check whether the given method is a create(...) method
    */
   public boolean isCreateMethod(Method m)
   {
      return m.getName().startsWith(CREATE_METHOD);
   }

   public boolean isEjbCreateMethod(Method m)
   {
      return m.getName().startsWith(EJB_CREATE_METHOD);
   }

   public boolean isEjbRemoveMethod(Method m)
   {
      return m.getName().startsWith(EJB_REMOVE_METHOD);
   }

   public boolean isEjbSelectMethod(Method m)
   {
      return m.getName().startsWith(EJB_SELECT_METHOD);
   }

   public boolean isEjbHomeMethod(Method m)
   {
      return m.getName().startsWith(EJB_HOME_METHOD);
   }

   /** Finds java.rmi.Remote interface from the class
    */
   public boolean hasRemoteInterface(Class c)
   {
      return isAssignableFrom("java.rmi.Remote", c);
   }

   /**
    * Return all ejbSelect methods
    */
   public Iterator getEjbSelectMethods(Class c)
   {
      List selects = new LinkedList();
      Method[] method = c.getMethods();

      for (int i = 0; i < method.length; ++i)
      {
         if (isEjbSelectMethod(method[i]))
         {
            selects.add(method[i]);
         }
      }

      return selects.iterator();
   }

   /**
    * Searches for an instance of an ejbRemove method from the class
    */
   public boolean hasEJBRemoveMethod(Class c)
   {
      Method[] method = c.getMethods();
      for (int i = 0; i < method.length; ++i)
      {
         if (isEjbRemoveMethod(method[i]))
            return true;
      }

      return false;
   }

   /**
    * Returns the ejbRemove(...) methods of a bean
    */
   public Iterator getEJBRemoveMethods(Class c)
   {
      List ejbRemoves = new LinkedList();
      Method[] method = c.getMethods();

      for (int i = 0; i < method.length; ++i)
      {
         if (isEjbRemoveMethod(method[i]))
            ejbRemoves.add(method[i]);
      }

      return ejbRemoves.iterator();
   }

   /**
    * Home methods are any method on the home interface which is
    * neither a create or find method.
    */
   public Iterator getHomeMethods(Class c)
   {
      List homes = new LinkedList();
      Method[] method = c.getMethods();

      for (int i = 0; i < method.length; ++i)
      {
         if (!isCreateMethod(method[i]) && !isFinderMethod(method[i]))
            homes.add(method[i]);
      }

      return homes.iterator();
   }

   public Iterator getEjbHomeMethods(Class c)
   {
      List homes = new LinkedList();
      Method[] method = c.getMethods();

      for (int i = 0; i < method.length; ++i)
      {
         if (isEjbHomeMethod(method[i]))
            homes.add(method[i]);
      }

      return homes.iterator();
   }

   /**
    * Check whether there is a matching &lt;query&gt; Element defined
    * for the Method m
    *
    * @param m Method to check, should be either a Finder or a Select
    * @param e EntityMetaData
    *
    * @return <code>true</code> if a matching &lt;query&gt; Element
    *         was located.
    */
   protected boolean hasMatchingQuery(Method m, EntityMetaData e)
   {
      boolean result = false;

      Iterator qIt = e.getQueries();
      while (qIt.hasNext())
      {
         QueryMetaData qmd = (QueryMetaData)qIt.next();

         // matching names
         if (!qmd.getMethodName().equals(m.getName()))
         {
            continue;
         }

         Class[] methodParameter = m.getParameterTypes();
         Class[] queryParameter = null;

         try
         {
            queryParameter = Classes.convertToJavaClasses(qmd.getMethodParams(), classloader);
         }
         catch (ClassNotFoundException cnfe)
         {
            // FIXME: this should be handled differently, especially
            //        there shouldn't be a DeploymentException being
            //        thrown ...
            continue;
         }

         // number of parameters has to match
         if (methodParameter.length != queryParameter.length)
         {
            continue;
         }

         // walk the parameter list and compare for equality
         boolean parametersMatch = true;
         for (int i = 0; i < methodParameter.length; i++)
         {
            if (!methodParameter[i].equals(queryParameter[i]))
            {
               parametersMatch = false;
               break;
            }
         }

         if (parametersMatch)
         {
            result = true;
            break;
         }
      }

      return result;
   }
}