Save This Page
Home » jboss-5.0.0.CR1-src » org » jboss » verifier » strategy » [javadoc | source]
    1   /*
    2   * JBoss, Home of Professional Open Source
    3   * Copyright 2005, JBoss Inc., and individual contributors as indicated
    4   * by the @authors tag. See the copyright.txt in the distribution for a
    5   * full listing of individual contributors.
    6   *
    7   * This is free software; you can redistribute it and/or modify it
    8   * under the terms of the GNU Lesser General Public License as
    9   * published by the Free Software Foundation; either version 2.1 of
   10   * the License, or (at your option) any later version.
   11   *
   12   * This software is distributed in the hope that it will be useful,
   13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
   15   * Lesser General Public License for more details.
   16   *
   17   * You should have received a copy of the GNU Lesser General Public
   18   * License along with this software; if not, write to the Free
   19   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
   20   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
   21   */
   22   package org.jboss.verifier.strategy;
   23   
   24   // standard imports
   25   
   26   import org.jboss.logging.Logger;
   27   import org.jboss.metadata.BeanMetaData;
   28   import org.jboss.metadata.EntityMetaData;
   29   import org.jboss.metadata.MessageDrivenMetaData;
   30   import org.jboss.util.Classes;
   31   import org.jboss.verifier.Section;
   32   import org.jboss.verifier.event.VerificationEvent;
   33   import org.jboss.verifier.factory.DefaultEventFactory;
   34   import org.jboss.verifier.factory.VerificationEventFactory;
   35   
   36   import java.lang.reflect.Constructor;
   37   import java.lang.reflect.Field;
   38   import java.lang.reflect.Member;
   39   import java.lang.reflect.Method;
   40   import java.lang.reflect.Modifier;
   41   import java.net.URL;
   42   import java.net.URLClassLoader;
   43   import java.rmi.RemoteException;
   44   import java.util.Arrays;
   45   import java.util.Iterator;
   46   import java.util.LinkedList;
   47   import java.util.List;
   48   
   49   import javax.jms.Message;
   50   
   51   
   52   /**
   53    * Abstract superclass for verifiers containing a bunch of useful methods.
   54    *
   55    * @see     org.jboss.verifier.strategy.VerificationStrategy
   56    *
   57    * @author <a href="mailto:juha.lindfors@jboss.org">Juha Lindfors</a>
   58    * @author  Aaron Mulder  (ammulder@alumni.princeton.edu)
   59    * @author  Vinay Menon   (menonv@cpw.co.uk)
   60    * @author <a href="mailto:andreas@jboss.org">Andreas Schaefer</a>
   61    * @author <a href="mailto:luke@mkeym.com">Luke Taylor</a>
   62    * @author <a href="mailto:jwalters@computer.org">Jay Walters</a>
   63    * @author Scott.Stark@jboss.org
   64    *
   65    * @version $Revision: 68983 $
   66    * @since   JDK 1.3
   67    */
   68   public abstract class AbstractVerifier
   69           implements VerificationStrategy
   70   {
   71      static final Logger log = Logger.getLogger(AbstractVerifier.class);
   72   
   73      protected final static String EJB_OBJECT_INTERFACE =
   74              "javax.ejb.EJBObject";
   75   
   76      protected final static String EJB_HOME_INTERFACE =
   77              "javax.ejb.EJBHome";
   78   
   79      protected final static String EJB_LOCAL_OBJECT_INTERFACE =
   80              "javax.ejb.EJBLocalObject";
   81   
   82      protected final static String EJB_LOCAL_HOME_INTERFACE =
   83              "javax.ejb.EJBLocalHome";
   84      
   85      /**
   86       * The application classloader. This can be provided by the context
   87       * directly via {@link VerificationContext#getClassLoader} method, or
   88       * constructed by this object by creating a classloader to the URL
   89       * returned by {@link VerificationContext#getJarLocation} method. <p>
   90       *
   91       * Initialized in the constructor.
   92       */
   93      protected ClassLoader classloader = null;
   94   
   95      /**
   96       * Factory for generating the verifier events. <p>
   97       *
   98       * Initialized in the constructor.
   99       *
  100       * @see org.jboss.verifier.factory.DefaultEventFactory
  101       */
  102      private VerificationEventFactory factory = null;
  103   
  104      /**
  105       * Context is used for retrieving application level information,
  106       * such as the application meta data, location of the jar file, etc.
  107       * <p>
  108       *
  109       * Initialized in the constructor.
  110       */
  111      private VerificationContext context = null;
  112   
  113      /**************************************************************************
  114       *
  115       *      CONSTRUCTORS
  116       *
  117       **************************************************************************/
  118      public AbstractVerifier(VerificationContext context)
  119      {
  120         this.context = context;
  121         this.classloader = context.getClassLoader();
  122         this.factory = new DefaultEventFactory(getMessageBundle());
  123   
  124         if (this.classloader == null)
  125         {
  126            URL[] list = {context.getJarLocation()};
  127   
  128            ClassLoader parent = Thread.currentThread().getContextClassLoader();
  129            this.classloader = new URLClassLoader(list, parent);
  130         }
  131      }
  132   
  133   
  134   /*
  135    *************************************************************************
  136    *
  137    *      PUBLIC INSTANCE METHODS
  138    *
  139    *************************************************************************
  140    */
  141   
  142      public boolean isAssignableFrom(String className, Class assignableFromClass)
  143      {
  144         try
  145         {
  146            Class clazz = this.classloader.loadClass(className);
  147            return clazz.isAssignableFrom(assignableFromClass);
  148         }
  149         catch (ClassNotFoundException e)
  150         {
  151            log.warn("Failed to find class: " + className, e);
  152         }
  153         return false;
  154      }
  155   
  156      public boolean isAssignableFrom(Class clazz, String assignableFromClassName)
  157      {
  158         try
  159         {
  160            Class assignableFromClass = this.classloader.loadClass(assignableFromClassName);
  161            return clazz.isAssignableFrom(assignableFromClass);
  162         }
  163         catch (ClassNotFoundException e)
  164         {
  165            log.warn("Failed to find class: " + assignableFromClassName, e);
  166         }
  167         return false;
  168      }
  169   
  170      public abstract String getMessageBundle();
  171   
  172      public abstract boolean isCreateMethod(Method m);
  173   
  174      public abstract boolean isEjbCreateMethod(Method m);
  175   
  176      public boolean hasLegalRMIIIOPArguments(Method method)
  177      {
  178         Class[] params = method.getParameterTypes();
  179   
  180         for (int i = 0; i < params.length; ++i)
  181         {
  182            if (!isRMIIIOPType(params[i]))
  183               return false;
  184         }
  185   
  186         return true;
  187      }
  188   
  189      public boolean hasLegalRMIIIOPReturnType(Method method)
  190      {
  191         return isRMIIIOPType(method.getReturnType());
  192      }
  193   
  194   
  195      public boolean hasLegalRMIIIOPExceptionTypes(Method method)
  196      {
  197         /*
  198          * All checked exception classes used in method declarations
  199          * (other than java.rmi.RemoteException) MUST be conforming
  200          * RMI/IDL exception types.
  201          *
  202          * Spec 28.2.3 (4)
  203          */
  204         Iterator it = Arrays.asList(method.getExceptionTypes()).iterator();
  205         while (it.hasNext())
  206         {
  207            Class exception = (Class)it.next();
  208   
  209            if (!isRMIIDLExceptionType(exception))
  210               return false;
  211         }
  212   
  213         return true;
  214      }
  215   
  216      /**
  217       * Checks if the method includes java.rmi.RemoteException or its
  218       * subclass in its throws clause.
  219       *
  220       * See bug report #434739 and #607805
  221       */
  222      public boolean throwsRemoteException(Method method)
  223      {
  224         Class[] exception = method.getExceptionTypes();
  225   
  226         for (int i = 0; i < exception.length; ++i)
  227         {
  228            // Fix for bug #607805: an IOException is OK for local interfaces
  229            // Fix for bug #626430: java.lang.Exception is also OK
  230            if (exception[i].equals(java.io.IOException.class)
  231                    || exception[i].equals(java.lang.Exception.class))
  232            {
  233               continue;
  234            }
  235   // Not true see bug report #434739
  236   //            if (java.rmi.RemoteException.class.isAssignableFrom(exception[i]))
  237   // According to the RMI spec. a remote interface must throw an RemoteException
  238   // or any of its super classes therefore the check must be done vice versa
  239   
  240            if (isAssignableFrom(exception[i], "java.rmi.RemoteException"))
  241            {
  242               return true;
  243            }
  244         }
  245   
  246         return false;
  247      }
  248   
  249      /**
  250       * checks if the method accepts a single parameter of a specified type.
  251       */
  252      public boolean hasSingleArgument(Method method, Class argClass)
  253      {
  254         Class[] params = method.getParameterTypes();
  255         if (params.length == 1)
  256         {
  257            if (params[0].equals(argClass))
  258               return true;
  259         }
  260   
  261         return false;
  262      }
  263   
  264      /**
  265       * checks if the method accepts any parameters.
  266       */
  267      public boolean hasNoArguments(Method method)
  268      {
  269         Class[] params = method.getParameterTypes();
  270         return (params.length == 0) ? true : false;
  271      }
  272   
  273      /**
  274       * checks if the method throws no checked exceptions in its throws clause.
  275       */
  276      public boolean throwsNoException(Method method)
  277      {
  278         boolean hasCheckedException = false;
  279         Class[] exceptions = method.getExceptionTypes();
  280         for (int e = 0; e < exceptions.length; e++)
  281         {
  282            Class ex = exceptions[e];
  283            boolean isError = Error.class.isAssignableFrom(ex);
  284            boolean isRuntimeException = RuntimeException.class.isAssignableFrom(ex);
  285            boolean isRemoteException = RemoteException.class.isAssignableFrom(ex);
  286            if (isError == false && isRuntimeException == false && isRemoteException == false)
  287               hasCheckedException = true;
  288         }
  289         return hasCheckedException == false;
  290      }
  291   
  292      /**
  293       * checks if the method includes java.ejb.CreateException in its
  294       * throws clause.
  295       */
  296      public boolean throwsCreateException(Method method)
  297      {
  298         Class[] exception = method.getExceptionTypes();
  299         for (int i = 0; i < exception.length; ++i)
  300         {
  301            if (isAssignableFrom("javax.ejb.CreateException", exception[i]))
  302               return true;
  303         }
  304   
  305         return false;
  306      }
  307   
  308      /**
  309       * checks if the methods includes javax.ejb.FinderException in its
  310       * throws clause.
  311       */
  312      public boolean throwsFinderException(Method method)
  313      {
  314         Class[] exception = method.getExceptionTypes();
  315   
  316         for (int i = 0; i < exception.length; ++i)
  317         {
  318            if (isAssignableFrom("javax.ejb.FinderException", exception[i]))
  319               return true;
  320         }
  321   
  322         return false;
  323      }
  324   
  325      /**
  326       * checks if a class's member (method, constructor or field) has a
  327       * <code>static</code> modifier.
  328       */
  329      public boolean isStatic(Member member)
  330      {
  331         return (Modifier.isStatic(member.getModifiers()));
  332      }
  333   
  334      /**
  335       * checks if the given class is declared as static (inner classes only)
  336       */
  337      public boolean isStatic(Class c)
  338      {
  339         return (Modifier.isStatic(c.getModifiers()));
  340      }
  341   
  342      /**
  343       * checks if a class's member (method, constructor or field) has a
  344       * <code>final</code> modifier.
  345       */
  346      public boolean isFinal(Member member)
  347      {
  348         return (Modifier.isFinal(member.getModifiers()));
  349      }
  350   
  351      /**
  352       * checks if the given class is declared as final
  353       */
  354      public boolean isFinal(Class c)
  355      {
  356         return (Modifier.isFinal(c.getModifiers()));
  357      }
  358   
  359      /**
  360       * checks if a class's member (method, constructor or field) has a
  361       * <code>public</code> modifier.
  362       */
  363      public boolean isPublic(Member member)
  364      {
  365         return (Modifier.isPublic(member.getModifiers()));
  366      }
  367   
  368      /**
  369       * checks if the given class is declared as <code>public</code>
  370       */
  371      public boolean isPublic(Class c)
  372      {
  373         return (Modifier.isPublic(c.getModifiers()));
  374      }
  375   
  376      /**
  377       * Checks whether all the fields in the class are declared as public.
  378       */
  379      public boolean isAllFieldsPublic(Class c)
  380      {
  381         try
  382         {
  383            Field list[] = c.getFields();
  384            for (int i = 0; i < list.length; i++)
  385            {
  386               if (!Modifier.isPublic(list[i].getModifiers()))
  387                  return false;
  388            }
  389         }
  390         catch (Exception e)
  391         {
  392            return false;
  393         }
  394   
  395         return true;
  396      }
  397   
  398      /**
  399       * checks if the given class is declared as abstract
  400       */
  401      public boolean isAbstract(Class c)
  402      {
  403         return (Modifier.isAbstract(c.getModifiers()));
  404      }
  405   
  406      /**
  407       * checks if the given method is declared as abstract
  408       */
  409      public boolean isAbstract(Method m)
  410      {
  411         return (Modifier.isAbstract(m.getModifiers()));
  412      }
  413   
  414      /**
  415       * checks if finder returns the primary key type
  416       */
  417      public boolean isSingleObjectFinder(EntityMetaData entity,
  418                                          Method finder)
  419      {
  420         return hasPrimaryKeyReturnType(entity, finder);
  421      }
  422   
  423      /**
  424       * checks if finder method returns either Collection or Enumeration
  425       */
  426      public boolean isMultiObjectFinder(Method f)
  427      {
  428         return (java.util.Collection.class.isAssignableFrom(f.getReturnType())
  429                 || java.util.Enumeration.class.isAssignableFrom(f.getReturnType()));
  430      }
  431   
  432      /**
  433       *  checks the return type of method matches the bean's remote interface
  434       */
  435      public boolean hasRemoteReturnType(BeanMetaData bean, Method m)
  436      {
  437         try
  438         {
  439            Class clazz = classloader.loadClass(bean.getRemote());
  440            return m.getReturnType().isAssignableFrom(clazz);
  441         }
  442         catch (Exception e)
  443         {
  444            // e.printStackTrace();
  445            return false;
  446         }
  447      }
  448   
  449      /**
  450       *  checks the return type of method matches the bean's local interface
  451       */
  452      public boolean hasLocalReturnType(BeanMetaData bean, Method m)
  453      {
  454         try
  455         {
  456            Class clazz = classloader.loadClass(bean.getLocal());
  457            return m.getReturnType().isAssignableFrom(clazz);
  458         }
  459         catch (Exception e)
  460         {
  461            // e.printStackTrace();
  462            return false;
  463         }
  464      }
  465   
  466      /**
  467       * checks if a method has a void return type
  468       */
  469      public boolean hasVoidReturnType(Method method)
  470      {
  471         return (method.getReturnType() == Void.TYPE);
  472      }
  473   
  474      /**
  475       * Finds java.ejb.MessageDrivenBean interface from the class
  476       */
  477      public boolean hasMessageDrivenBeanInterface(Class c)
  478      {
  479         return isAssignableFrom("javax.ejb.MessageDrivenBean", c);
  480      }
  481   
  482      /**
  483       * Finds javax.jms.MessageListener interface from the class
  484       */
  485      public boolean hasMessageListenerInterface(Class c)
  486      {
  487         return isAssignableFrom("javax.jms.MessageListener", c);
  488      }
  489   
  490      /**
  491       * Finds java.ejb.SessionBean interface from the class
  492       */
  493      public boolean hasSessionBeanInterface(Class c)
  494      {
  495         return isAssignableFrom("javax.ejb.SessionBean", c);
  496      }
  497   
  498      /**
  499       * Finds java.ejb.EntityBean interface from the class
  500       */
  501      public boolean hasEntityBeanInterface(Class c)
  502      {
  503         return isAssignableFrom("javax.ejb.EntityBean", c);
  504      }
  505   
  506      /**
  507       * Finds java.ejb.EJBObject interface from the class
  508       */
  509      public boolean hasEJBObjectInterface(Class c)
  510      {
  511         return isAssignableFrom("javax.ejb.EJBObject", c);
  512      }
  513   
  514      /**
  515       * Finds java.ejb.EJBLocalObject interface from the class
  516       */
  517      public boolean hasEJBLocalObjectInterface(Class c)
  518      {
  519         return isAssignableFrom("javax.ejb.EJBLocalObject", c);
  520      }
  521   
  522      /**
  523       * Finds javax.ejb.EJBHome interface from the class or its
  524       * superclasses
  525       */
  526      public boolean hasEJBHomeInterface(Class c)
  527      {
  528         return isAssignableFrom("javax.ejb.EJBHome", c);
  529      }
  530   
  531      /**
  532       * Finds javax.ejb.EJBLocalHome interface from the class or its
  533       * superclasses
  534       */
  535      public boolean hasEJBLocalHomeInterface(Class c)
  536      {
  537         return isAssignableFrom("javax.ejb.EJBLocalHome", c);
  538      }
  539   
  540      /**
  541       * Finds javax.ejb.SessionSynchronization interface from the class
  542       */
  543      public boolean hasSessionSynchronizationInterface(Class c)
  544      {
  545         return isAssignableFrom("javax.ejb.SessionSynchronization", c);
  546      }
  547   
  548      /**
  549       * Checks if a class has a default (no args) constructor
  550       */
  551      public boolean hasDefaultConstructor(Class c)
  552      {
  553         try
  554         {
  555            Constructor ctr = c.getConstructor(new Class[0]);
  556         }
  557         catch (NoSuchMethodException e)
  558         {
  559            if( log.isTraceEnabled() )
  560            {
  561               StringBuffer tmp = new StringBuffer("hasDefaultConstructor(");
  562               tmp.append(") failure, ");
  563               Classes.displayClassInfo(c, tmp);
  564               log.trace(tmp.toString(), e);
  565            }
  566            return false;
  567         }
  568   
  569         return true;
  570      }
  571   
  572      /**
  573       * Checks of the class defines a finalize() method
  574       */
  575      public boolean hasFinalizer(Class c)
  576      {
  577         try
  578         {
  579            Method finalizer = c.getDeclaredMethod(FINALIZE_METHOD, new Class[0]);
  580         }
  581         catch (NoSuchMethodException e)
  582         {
  583            return false;
  584         }
  585   
  586         return true;
  587      }
  588   
  589      /**
  590       * check if a class has one or more finder methods
  591       */
  592      public boolean hasFinderMethod(Class c)
  593      {
  594         Method[] method = c.getMethods();
  595         for (int i = 0; i < method.length; ++i)
  596         {
  597            if (method[i].getName().startsWith("ejbFind"))
  598               return true;
  599         }
  600   
  601         return false;
  602      }
  603   
  604      /**
  605       * Check if this is a finder method
  606       */
  607      public boolean isFinderMethod(Method m)
  608      {
  609         return (m.getName().startsWith("find"));
  610      }
  611   
  612      /**
  613       * Check if the given message is the onMessage() method
  614       */
  615      public boolean isOnMessageMethod(Method m)
  616      {
  617         if ("onMessage".equals(m.getName()))
  618         {
  619            Class[] paramTypes = m.getParameterTypes();
  620            if (paramTypes.length == 1)
  621            {
  622               if (Message.class.equals(paramTypes[0]))
  623                  return true;
  624            }
  625         }
  626         return false;
  627      }
  628      
  629      /**
  630       * Checks for at least one non-static field.
  631       */
  632      public boolean hasANonStaticField(Class c)
  633      {
  634         try
  635         {
  636            Field list[] = c.getFields();
  637            for (int i = 0; i < list.length; i++)
  638            {
  639               if (!Modifier.isStatic(list[i].getModifiers()))
  640                  return true;
  641            }
  642         }
  643         catch (Exception ignored)
  644         {
  645         }
  646   
  647         return false;
  648      }
  649   
  650      /**
  651       * Searches for an instance of a public onMessage method from the class
  652       */
  653      public boolean hasOnMessageMethod(Class c)
  654      {
  655         Method[] method = c.getMethods();
  656         for (int i = 0; i < method.length; ++i)
  657         {
  658            if (isOnMessageMethod(method[i]))
  659               return true;
  660         }
  661   
  662         return false;
  663      }
  664   
  665      /**
  666       * Searches for an instance of a public create method from the class
  667       */
  668      public boolean hasCreateMethod(Class c)
  669      {
  670         Method[] method = c.getMethods();
  671   
  672         for (int i = 0; i < method.length; ++i)
  673         {
  674            if (isCreateMethod(method[i]))
  675               return true;
  676         }
  677   
  678         return false;
  679      }
  680   
  681      /**
  682       * Searches for an instance of a public ejbCreate method from the class
  683       */
  684      public boolean hasEJBCreateMethod(Class c, boolean isSession)
  685      {
  686         Method[] method = c.getMethods();
  687         for (int i = 0; i < method.length; ++i)
  688         {
  689            if (isEjbCreateMethod(method[i]))
  690            {
  691               if (!isStatic(method[i]) && !isFinal(method[i])
  692                       && ((isSession && hasVoidReturnType(method[i]))
  693                       || (!isSession))
  694               )
  695               {
  696                  return true;
  697               }
  698            }
  699         }
  700   
  701         return false;
  702      }
  703   
  704      /**
  705       * Searches the class or interface, and its superclass or superinterface
  706       * for a create() method that takes no arguments
  707       */
  708      public boolean hasDefaultCreateMethod(Class home)
  709      {
  710         Method[] method = home.getMethods();
  711   
  712         for (int i = 0; i < method.length; ++i)
  713         {
  714            if (isCreateMethod(method[i]))
  715            {
  716               Class[] params = method[i].getParameterTypes();
  717               if (params.length == 0)
  718                  return true;
  719            }
  720         }
  721   
  722         return false;
  723      }
  724   
  725      /**
  726       * checks if the class has an ejbFindByPrimaryKey method
  727       */
  728      public boolean hasEJBFindByPrimaryKey(Class c)
  729      {
  730         Method[] method = c.getMethods();
  731         for (int i = 0; i < method.length; ++i)
  732         {
  733            if (method[i].getName().equals(EJB_FIND_BY_PRIMARY_KEY))
  734               return true;
  735         }
  736   
  737         return false;
  738      }
  739   
  740      /**
  741       * checks the return type of method matches the entity's primary key
  742       * class or is a super class of the primary key class
  743       */
  744      public boolean hasPrimaryKeyReturnType(EntityMetaData entity, Method m)
  745      {
  746         try
  747         {
  748            return
  749                    m.getReturnType().isAssignableFrom(classloader.loadClass(entity.getPrimaryKeyClass()));
  750         }
  751         catch (ClassNotFoundException cnfe)
  752         {
  753            // Only check equality
  754            return
  755                    m.getReturnType().getName().equals(entity.getPrimaryKeyClass());
  756         }
  757      }
  758   
  759      /**
  760       * @return Returns the default create method or <code>null</code>
  761       *  if none is found
  762       */
  763      public Method getDefaultCreateMethod(Class c)
  764      {
  765         Method method = null;
  766   
  767         try
  768         {
  769            method = c.getMethod(CREATE_METHOD, null);
  770         }
  771         catch (NoSuchMethodException ignored)
  772         {
  773         }
  774   
  775         return method;
  776      }
  777   
  778      /**
  779       * Returns the ejbFindByPrimaryKey method
  780       */
  781      public Method getEJBFindByPrimaryKey(Class c)
  782      {
  783         Method[] method = c.getMethods();
  784         for (int i = 0; i < method.length; ++i)
  785         {
  786            if (method[i].getName().equals(EJB_FIND_BY_PRIMARY_KEY))
  787               return method[i];
  788         }
  789   
  790         return null;
  791      }
  792   
  793      /**
  794       * returns the ejbFind<METHOD> methods of a bean
  795       */
  796      public Iterator getEJBFindMethods(Class c)
  797      {
  798         List finders = new LinkedList();
  799         Method[] method = c.getMethods();
  800         for (int i = 0; i < method.length; ++i)
  801         {
  802            if (method[i].getName().startsWith("ejbFind"))
  803               finders.add(method[i]);
  804         }
  805   
  806         return finders.iterator();
  807      }
  808   
  809   
  810      /**
  811       * returns the finder methods of a home interface
  812       */
  813      public Iterator getFinderMethods(Class home)
  814      {
  815         List finders = new LinkedList();
  816         Method[] method = home.getMethods();
  817   
  818         for (int i = 0; i < method.length; ++i)
  819         {
  820            if (method[i].getName().startsWith("find"))
  821               finders.add(method[i]);
  822         }
  823   
  824         return finders.iterator();
  825      }
  826   
  827      /**
  828       * Returns the onMessage(...) method of a bean
  829       */
  830      public Iterator getOnMessageMethods(Class c)
  831      {
  832         List onMessages = new LinkedList();
  833         Method[] method = c.getMethods();
  834   
  835         for (int i = 0; i < method.length; ++i)
  836         {
  837            if (isOnMessageMethod(method[i]))
  838               onMessages.add(method[i]);
  839         }
  840   
  841         return onMessages.iterator();
  842      }
  843   
  844      /**
  845       * Returns the ejbCreate(...) methods of a bean
  846       */
  847      public Iterator getEJBCreateMethods(Class c)
  848      {
  849         List ejbCreates = new LinkedList();
  850         Method[] method = c.getMethods();
  851   
  852         for (int i = 0; i < method.length; ++i)
  853         {
  854            if (isEjbCreateMethod(method[i]))
  855               ejbCreates.add(method[i]);
  856         }
  857   
  858         return ejbCreates.iterator();
  859      }
  860   
  861      /**
  862       * Return all create methods of a class
  863       */
  864      public Iterator getCreateMethods(Class c)
  865      {
  866         List creates = new LinkedList();
  867         Method[] method = c.getMethods();
  868   
  869         for (int i = 0; i < method.length; ++i)
  870         {
  871            if (isCreateMethod(method[i]))
  872               creates.add(method[i]);
  873         }
  874   
  875         return creates.iterator();
  876      }
  877   
  878      /**
  879       * Check whether a class has more than one create method
  880       */
  881      public boolean hasMoreThanOneCreateMethods(Class c)
  882      {
  883         int count = 0;
  884         Method[] method = c.getMethods();
  885         for (int i = 0; i < method.length; ++i)
  886         {
  887            if (isCreateMethod(method[i]))
  888            {
  889               ++count;
  890            }
  891         }
  892   
  893         return (count > 1);
  894      }
  895   
  896      /**
  897       * Check whether two given methods declare the same Exceptions
  898       */
  899      public boolean hasMatchingExceptions(Method source, Method target)
  900      {
  901         // target must be a superset of source
  902         Class[] a = source.getExceptionTypes();
  903         Class[] b = target.getExceptionTypes();
  904         Class rteClass = null;
  905         Class errorClass = null;
  906   
  907         try
  908         {
  909            rteClass = classloader.loadClass("java.lang.RuntimeException");
  910            errorClass = classloader.loadClass("java.lang.Error");
  911         }
  912         catch (ClassNotFoundException cnfe)
  913         {
  914            // Ignored, if this happens we have more serious problems :)
  915         }
  916   
  917         for (int i = 0; i < a.length; ++i)
  918         {
  919            if (rteClass.isAssignableFrom(a[i])
  920                    || errorClass.isAssignableFrom(a[i]))
  921            {
  922               // Skip over subclasses of java.lang.RuntimeException and
  923               // java.lang.Error
  924               continue;
  925            }
  926   
  927            boolean found = false;
  928            for (int j = 0; j < b.length; ++j)
  929            {
  930               if (b[j].isAssignableFrom(a[i]))
  931               {
  932                  found = true;
  933                  break;
  934               }
  935            }
  936   
  937            if (!found)
  938            {
  939               return false;
  940            }
  941         }
  942   
  943         return true;
  944      }
  945   
  946      /**
  947       * Check if a class (or its superclasses) declare a given method
  948       */
  949      public boolean hasMatchingMethod(Class bean, Method method)
  950      {
  951         try
  952         {
  953            bean.getMethod(method.getName(), method.getParameterTypes());
  954            return true;
  955         }
  956         catch (NoSuchMethodException e)
  957         {
  958            if( log.isTraceEnabled() )
  959            {
  960               StringBuffer tmp = new StringBuffer("hasMatchingMethod(");
  961               tmp.append(method.toString());
  962               tmp.append(") failure, ");
  963               Classes.displayClassInfo(bean, tmp);
  964               log.trace(tmp.toString(), e);
  965            }
  966            return false;
  967         }
  968      }
  969   
  970      /**
  971       * Check whether two methods have the same return type
  972       */
  973      public boolean hasMatchingReturnType(Method a, Method b)
  974      {
  975         return (a.getReturnType() == b.getReturnType());
  976      }
  977   
  978      /**
  979       * Check whether a bean has a matching ejbPostCreate methods for
  980       * a given ejbCreate method
  981       */
  982      public boolean hasMatchingEJBPostCreate(Class bean, Method create)
  983      {
  984         try
  985         {
  986            return (bean.getMethod(getMatchingEJBPostCreateName(create.getName()),
  987                    create.getParameterTypes()) != null);
  988         }
  989         catch (NoSuchMethodException e)
  990         {
  991            if( log.isTraceEnabled() )
  992            {
  993               StringBuffer tmp = new StringBuffer("hasMatchingEJBPostCreate(");
  994               tmp.append(create.toString());
  995               tmp.append(") failure, ");
  996               Classes.displayClassInfo(bean, tmp);
  997               log.trace(tmp.toString(), e);
  998            }
  999            return false;
 1000         }
 1001      }
 1002   
 1003      public boolean hasMatchingEJBCreate(Class bean, Method create)
 1004      {
 1005         try
 1006         {
 1007            return (bean.getMethod(getMatchingEJBCreateName(create.getName()), create.getParameterTypes()) != null);
 1008         }
 1009         catch (NoSuchMethodException e)
 1010         {
 1011            if( log.isTraceEnabled() )
 1012            {
 1013               StringBuffer tmp = new StringBuffer("hasMatchingEJBCreate(");
 1014               tmp.append(create.toString());
 1015               tmp.append(") failure, ");
 1016               Classes.displayClassInfo(bean, tmp);
 1017               log.trace(tmp.toString(), e);
 1018            }
 1019            return false;
 1020         }
 1021      }
 1022   
 1023      public Method getMatchingEJBPostCreate(Class bean, Method create)
 1024      {
 1025         try
 1026         {
 1027            return bean.getMethod(getMatchingEJBPostCreateName(create.getName()), create.getParameterTypes());
 1028         }
 1029         catch (NoSuchMethodException e)
 1030         {
 1031            return null;
 1032         }
 1033      }
 1034   
 1035      public Method getMatchingEJBCreate(Class bean, Method create)
 1036      {
 1037         try
 1038         {
 1039            return bean.getMethod(getMatchingEJBCreateName(create.getName()), create.getParameterTypes());
 1040         }
 1041         catch (NoSuchMethodException e)
 1042         {
 1043            return null;
 1044         }
 1045      }
 1046   
 1047      public boolean hasMatchingEJBFind(Class bean, Method finder)
 1048      {
 1049         try
 1050         {
 1051            String methodName = "ejbF" + finder.getName().substring(1);
 1052            return (bean.getMethod(methodName, finder.getParameterTypes()) != null);
 1053         }
 1054         catch (NoSuchMethodException e)
 1055         {
 1056            if( log.isTraceEnabled() )
 1057            {
 1058               StringBuffer tmp = new StringBuffer("hasMatchingEJBFind(");
 1059               tmp.append(finder.toString());
 1060               tmp.append(") failure, ");
 1061               Classes.displayClassInfo(bean, tmp);
 1062               log.trace(tmp.toString(), e);
 1063            }
 1064            return false;
 1065         }
 1066      }
 1067   
 1068      public Method getMatchingEJBFind(Class bean, Method finder)
 1069      {
 1070         try
 1071         {
 1072            String methodName = "ejbF" + finder.getName().substring(1);
 1073            return bean.getMethod(methodName, finder.getParameterTypes());
 1074         }
 1075         catch (NoSuchMethodException e)
 1076         {
 1077            return null;
 1078         }
 1079      }
 1080   
 1081      public boolean hasMatchingEJBHome(Class bean, Method home)
 1082      {
 1083         try
 1084         {
 1085            return (bean.getMethod(getMatchingEJBHomeName(home.getName()), home.getParameterTypes()) != null);
 1086         }
 1087         catch (NoSuchMethodException e)
 1088         {
 1089            if( log.isTraceEnabled() )
 1090            {
 1091               StringBuffer tmp = new StringBuffer("hasMatchingEJBHome(");
 1092               tmp.append(home.toString());
 1093               tmp.append(") failure, ");
 1094               Classes.displayClassInfo(bean, tmp);
 1095               log.trace(tmp.toString(), e);
 1096            }
 1097            return false;
 1098         }
 1099      }
 1100   
 1101   
 1102   /*
 1103    *************************************************************************
 1104    *
 1105    *      PROTECTED INSTANCE METHODS
 1106    *
 1107    *************************************************************************
 1108    */
 1109   
 1110      protected void fireSpecViolationEvent(BeanMetaData bean, Section section)
 1111      {
 1112         fireSpecViolationEvent(bean, null /* method */, section);
 1113      }
 1114   
 1115      protected void fireSpecViolationEvent(BeanMetaData bean, Method method,
 1116                                            Section section)
 1117      {
 1118         VerificationEvent event = factory.createSpecViolationEvent(context,
 1119                 section);
 1120         event.setName(bean.getEjbName());
 1121         event.setMethod(method);
 1122   
 1123         context.fireSpecViolation(event);
 1124      }
 1125   
 1126      protected final void fireBeanVerifiedEvent(BeanMetaData bean)
 1127      {
 1128         fireBeanVerifiedEvent(bean, null);
 1129      }
 1130   
 1131      protected final void fireBeanVerifiedEvent(BeanMetaData bean, String msg)
 1132      {
 1133         VerificationEvent event = factory.createBeanVerifiedEvent(context);
 1134         event.setName(bean.getEjbName());
 1135   
 1136         if (msg != null)
 1137         {
 1138            event.setMessage(msg);
 1139         }
 1140   
 1141         context.fireBeanChecked(event);
 1142      }
 1143   
 1144   /*
 1145    *************************************************************************
 1146    *
 1147    *      IMPLEMENTS VERIFICATIONSTRATEGY INTERFACE
 1148    *
 1149    *************************************************************************
 1150    */
 1151   
 1152      /**
 1153       * Provides an empty default implementation for EJB 1.1 verifier (message
 1154       * beans are for EJB 2.0 and greater only).
 1155       *
 1156       * @param bean  the message bean to verify
 1157       */
 1158      public void checkMessageBean(MessageDrivenMetaData bean)
 1159      {
 1160      }
 1161   
 1162      /**
 1163       * Returns the context object reference for this strategy implementation.
 1164       *
 1165       * @return  the client object using this algorithm implementation
 1166       */
 1167      public VerificationContext getContext()
 1168      {
 1169         return context;
 1170      }
 1171   
 1172   
 1173   /*
 1174    *************************************************************************
 1175    *
 1176    *      PRIVATE INSTANCE METHODS
 1177    *
 1178    *************************************************************************
 1179    */
 1180   
 1181      protected boolean isRMIIIOPType(Class type)
 1182      {
 1183         /*
 1184          *  Java Language to IDL Mapping
 1185          *
 1186          *  ftp://ftp.omg.org/pub/docs/ptc/99-03-09.pdf
 1187          *
 1188          *  A conforming RMI/IDL type is a Java type whose values may be
 1189          *  transmitted across an RMI/IDL remote interface at run-time.
 1190          *  A Java data type is a conforming RMI/IDL type if it is:
 1191          *
 1192          *  - one of the Java primitive types (see Primitive Types on
 1193          *    page 28-2).
 1194          *  - a conforming remote interface (as defined in RMI/IDL
 1195          *    Remote Interfaces on page 28-2).
 1196          *  - a conforming value type (as defined in RMI/IDL Value Types
 1197          *    on page 28-4).
 1198          *  - an array of conforming RMI/IDL types (see RMI/IDL Arrays on
 1199          *    page 28-5).
 1200          *  - a conforming exception type (see RMI/IDL Exception Types on
 1201          *    page 28-5).
 1202          *  - a conforming CORBA object reference type (see CORBA Object
 1203          *    Reference Types on page 28-6).
 1204          *  - a conforming IDL entity type see IDL Entity Types on page
 1205          *    28-6).
 1206          */
 1207   
 1208         /*
 1209          * Primitive types.
 1210          *
 1211          * Spec 28.2.2
 1212          */
 1213         if (type.isPrimitive())
 1214            return true;
 1215   
 1216         /*
 1217          * Conforming array.
 1218          *
 1219          * Spec 28.2.5
 1220          */
 1221         if (type.isArray())
 1222            return isRMIIIOPType(type.getComponentType());
 1223   
 1224         /*
 1225          * Conforming CORBA reference type
 1226          *
 1227          * Spec 28.2.7
 1228          */
 1229         if (org.omg.CORBA.Object.class.isAssignableFrom(type))
 1230            return true;
 1231   
 1232         /*
 1233          * Conforming IDL Entity type
 1234          *
 1235          * Spec 28.2.8
 1236          */
 1237         if (org.omg.CORBA.portable.IDLEntity.class.isAssignableFrom(type))
 1238            return true;
 1239   
 1240         /*
 1241          * Conforming remote interface.
 1242          *
 1243          * Spec 28.2.3
 1244          */
 1245         if (isRMIIDLRemoteInterface(type))
 1246            return true;
 1247   
 1248         /*
 1249          * Conforming exception.
 1250          *
 1251          * Spec 28.2.6
 1252          */
 1253         if (isRMIIDLExceptionType(type))
 1254            return true;
 1255   
 1256         /*
 1257          * Conforming value type.
 1258          *
 1259          * Spec 28.2.4
 1260          */
 1261         if (isRMIIDLValueType(type))
 1262            return true;
 1263   
 1264         return false;
 1265      }
 1266   
 1267      private boolean isRMIIDLRemoteInterface(Class type)
 1268      {
 1269         /*
 1270          * If does not implement java.rmi.Remote, cannot be valid RMI-IDL
 1271          * remote interface.
 1272          */
 1273   
 1274         if (!java.rmi.Remote.class.isAssignableFrom(type))
 1275            return false;
 1276   
 1277         Iterator methodIterator = Arrays.asList(type.getMethods()).iterator();
 1278         while (methodIterator.hasNext())
 1279         {
 1280            Method m = (Method)methodIterator.next();
 1281   
 1282            /*
 1283             * All methods in the interface MUST throw
 1284             * java.rmi.RemoteException or its subclass.
 1285             *
 1286             * Spec 28.2.3 (2)
 1287             */
 1288            if (!throwsRemoteException(m))
 1289               return false;
 1290   
 1291            /*
 1292             * All checked exception classes used in method declarations
 1293             * (other than java.rmi.RemoteException) MUST be conforming
 1294             * RMI/IDL exception types.
 1295             *
 1296             * Spec 28.2.3 (4)
 1297             */
 1298            Iterator it = Arrays.asList(m.getExceptionTypes()).iterator();
 1299            while (it.hasNext())
 1300            {
 1301               Class exception = (Class)it.next();
 1302               if (!isRMIIDLExceptionType(exception))
 1303                  return false;
 1304            }
 1305         }
 1306   
 1307         /*
 1308          * The constant values defined in the interface MUST be
 1309          * compile-time types of RMI/IDL primitive types or String.
 1310          *
 1311          * Spec 28.2.3 (6)
 1312          */
 1313         Iterator fieldIterator = Arrays.asList(type.getFields()).iterator();
 1314         while (fieldIterator.hasNext())
 1315         {
 1316            Field f = (Field)fieldIterator.next();
 1317   
 1318            if (f.getType().isPrimitive())
 1319               continue;
 1320   
 1321            if (f.getType().equals(java.lang.String.class))
 1322               continue;
 1323   
 1324            return false;
 1325         }
 1326   
 1327         return true;
 1328      }
 1329   
 1330      private boolean isRMIIDLExceptionType(Class type)
 1331      {
 1332         /*
 1333          * A conforming RMI/IDL Exception class MUST be a checked
 1334          * exception class and MUST be a valid RMI/IDL value type.
 1335          *
 1336          * Spec 28.2.6
 1337          */
 1338         if (!Throwable.class.isAssignableFrom(type))
 1339            return false;
 1340   
 1341         if (Error.class.isAssignableFrom(type))
 1342            return false;
 1343   
 1344   // 28.3.4.4 (6)  java.rmi.RemoteException and its subclasses, and unchecked
 1345   //               exception classes, are assumed to be mapped to the implicit
 1346   //               CORBA system exception, and are therefore not explicitly
 1347   //               declared in OMG IDL.
 1348   //
 1349   //        if (RuntimeException.class.isAssignableFrom(type))
 1350   //            return false;
 1351   
 1352         if (!isRMIIDLValueType(type))
 1353            return false;
 1354   
 1355         return true;
 1356      }
 1357   
 1358      protected boolean isRMIIDLValueType(Class type)
 1359      {
 1360         /*
 1361          * A value type MUST NOT either directly or indirectly implement the
 1362          * java.rmi.Remote interface.
 1363          *
 1364          * Spec 28.2.4 (4)
 1365          */
 1366         if (java.rmi.Remote.class.isAssignableFrom(type))
 1367            return false;
 1368   
 1369         /*
 1370          * If class is a non-static inner class then its containing class must
 1371          * also be a conforming RMI/IDL value type.
 1372          *
 1373          * Spec 28.2.4 (3)
 1374          */
 1375         if (type.getDeclaringClass() != null && !isStatic(type))
 1376         {
 1377            if (!isRMIIDLValueType(type.getDeclaringClass()))
 1378               return false;
 1379         }
 1380   
 1381         return true;
 1382      }
 1383   
 1384      private String getMatchingEJBHomeName(String homeName)
 1385      {
 1386         return "ejbHome" + homeName.substring(0, 1).toUpperCase() +
 1387                 homeName.substring(1);
 1388      }
 1389   
 1390      private String getMatchingEJBCreateName(String createName)
 1391      {
 1392         return "ejb" + createName.substring(0, 1).toUpperCase() +
 1393                 createName.substring(1);
 1394      }
 1395   
 1396      private String getMatchingEJBPostCreateName(String createName)
 1397      {
 1398         int createIdx = createName.indexOf("Create");
 1399         return "ejbPost" + createName.substring(createIdx >= 0 ? createIdx : 0);
 1400      }
 1401   
 1402   /*
 1403    *************************************************************************
 1404    *
 1405    *      STRING CONSTANTS
 1406    *
 1407    *************************************************************************
 1408    */
 1409   
 1410      /*
 1411       * Ejb-jar DTD
 1412       */
 1413      public final static String BEAN_MANAGED_TX =
 1414              "Bean";
 1415   
 1416      public final static String CONTAINER_MANAGED_TX =
 1417              "Container";
 1418   
 1419      public final static String STATEFUL_SESSION =
 1420              "Stateful";
 1421   
 1422      public final static String STATELESS_SESSION =
 1423              "Stateless";
 1424   
 1425      /*
 1426       * method names
 1427       */
 1428      private final static String EJB_FIND_BY_PRIMARY_KEY =
 1429              "ejbFindByPrimaryKey";
 1430   
 1431      protected final static String EJB_CREATE_METHOD =
 1432              "ejbCreate";
 1433   
 1434      protected final static String EJB_REMOVE_METHOD =
 1435              "ejbRemove";
 1436   
 1437      private final static String EJB_POST_CREATE_METHOD =
 1438              "ejbPostCreate";
 1439   
 1440      protected final static String CREATE_METHOD =
 1441              "create";
 1442   
 1443      protected final static String EJB_HOME_METHOD =
 1444              "ejbHome";
 1445   
 1446      protected final static String EJB_SELECT_METHOD =
 1447              "ejbSelect";
 1448   
 1449      private final static String FINALIZE_METHOD =
 1450              "finalize";
 1451   
 1452      private final static String REMOVE_METHOD =
 1453              "remove";
 1454   
 1455      private final static String GET_HOME_HANDLE_METHOD =
 1456              "getHomeHandle";
 1457   
 1458      private final static String GET_EJB_METADATA_METHOD =
 1459              "getEJBMetaData";
 1460   }
 1461   
 1462   /*
 1463   vim:ts=3:sw=3:et
 1464   */

Save This Page
Home » jboss-5.0.0.CR1-src » org » jboss » verifier » strategy » [javadoc | source]