0001: /*
0002: * JBoss, Home of Professional Open Source.
0003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
0004: * as indicated by the @author tags. See the copyright.txt file in the
0005: * distribution for a full listing of individual contributors.
0006: *
0007: * This is free software; you can redistribute it and/or modify it
0008: * under the terms of the GNU Lesser General Public License as
0009: * published by the Free Software Foundation; either version 2.1 of
0010: * the License, or (at your option) any later version.
0011: *
0012: * This software is distributed in the hope that it will be useful,
0013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0015: * Lesser General Public License for more details.
0016: *
0017: * You should have received a copy of the GNU Lesser General Public
0018: * License along with this software; if not, write to the Free
0019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
0020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
0021: */
0022: package org.jboss.verifier.strategy;
0023:
0024: // standard imports
0025:
0026: import org.gjt.lindfors.pattern.StrategyContext;
0027: import org.jboss.logging.Logger;
0028: import org.jboss.metadata.BeanMetaData;
0029: import org.jboss.metadata.EntityMetaData;
0030: import org.jboss.metadata.MessageDrivenMetaData;
0031: import org.jboss.util.Classes;
0032: import org.jboss.verifier.Section;
0033: import org.jboss.verifier.event.VerificationEvent;
0034: import org.jboss.verifier.factory.DefaultEventFactory;
0035: import org.jboss.verifier.factory.VerificationEventFactory;
0036:
0037: import java.lang.reflect.Constructor;
0038: import java.lang.reflect.Field;
0039: import java.lang.reflect.Member;
0040: import java.lang.reflect.Method;
0041: import java.lang.reflect.Modifier;
0042: import java.net.URL;
0043: import java.net.URLClassLoader;
0044: import java.rmi.RemoteException;
0045: import java.util.Arrays;
0046: import java.util.Iterator;
0047: import java.util.LinkedList;
0048: import java.util.List;
0049:
0050: import javax.jms.Message;
0051:
0052: /**
0053: * Abstract superclass for verifiers containing a bunch of useful methods.
0054: *
0055: * @see org.jboss.verifier.strategy.VerificationStrategy
0056: *
0057: * @author <a href="mailto:juha.lindfors@jboss.org">Juha Lindfors</a>
0058: * @author Aaron Mulder (ammulder@alumni.princeton.edu)
0059: * @author Vinay Menon (menonv@cpw.co.uk)
0060: * @author <a href="mailto:andreas@jboss.org">Andreas Schaefer</a>
0061: * @author <a href="mailto:luke@mkeym.com">Luke Taylor</a>
0062: * @author <a href="mailto:jwalters@computer.org">Jay Walters</a>
0063: * @author Scott.Stark@jboss.org
0064: *
0065: * @version $Revision: 57209 $
0066: * @since JDK 1.3
0067: */
0068: public abstract class AbstractVerifier implements VerificationStrategy {
0069: static final Logger log = Logger.getLogger(AbstractVerifier.class);
0070:
0071: protected final static String EJB_OBJECT_INTERFACE = "javax.ejb.EJBObject";
0072:
0073: protected final static String EJB_HOME_INTERFACE = "javax.ejb.EJBHome";
0074:
0075: protected final static String EJB_LOCAL_OBJECT_INTERFACE = "javax.ejb.EJBLocalObject";
0076:
0077: protected final static String EJB_LOCAL_HOME_INTERFACE = "javax.ejb.EJBLocalHome";
0078:
0079: /**
0080: * The application classloader. This can be provided by the context
0081: * directly via {@link VerificationContext#getClassLoader} method, or
0082: * constructed by this object by creating a classloader to the URL
0083: * returned by {@link VerificationContext#getJarLocation} method. <p>
0084: *
0085: * Initialized in the constructor.
0086: */
0087: protected ClassLoader classloader = null;
0088:
0089: /**
0090: * Factory for generating the verifier events. <p>
0091: *
0092: * Initialized in the constructor.
0093: *
0094: * @see org.jboss.verifier.factory.DefaultEventFactory
0095: */
0096: private VerificationEventFactory factory = null;
0097:
0098: /**
0099: * Context is used for retrieving application level information,
0100: * such as the application meta data, location of the jar file, etc.
0101: * <p>
0102: *
0103: * Initialized in the constructor.
0104: */
0105: private VerificationContext context = null;
0106:
0107: /**************************************************************************
0108: *
0109: * CONSTRUCTORS
0110: *
0111: **************************************************************************/
0112: public AbstractVerifier(VerificationContext context) {
0113: this .context = context;
0114: this .classloader = context.getClassLoader();
0115: this .factory = new DefaultEventFactory(getMessageBundle());
0116:
0117: if (this .classloader == null) {
0118: URL[] list = { context.getJarLocation() };
0119:
0120: ClassLoader parent = Thread.currentThread()
0121: .getContextClassLoader();
0122: this .classloader = new URLClassLoader(list, parent);
0123: }
0124: }
0125:
0126: /*
0127: *************************************************************************
0128: *
0129: * PUBLIC INSTANCE METHODS
0130: *
0131: *************************************************************************
0132: */
0133:
0134: public boolean isAssignableFrom(String className,
0135: Class assignableFromClass) {
0136: try {
0137: Class clazz = this .classloader.loadClass(className);
0138: return clazz.isAssignableFrom(assignableFromClass);
0139: } catch (ClassNotFoundException e) {
0140: log.warn("Failed to find class: " + className, e);
0141: }
0142: return false;
0143: }
0144:
0145: public boolean isAssignableFrom(Class clazz,
0146: String assignableFromClassName) {
0147: try {
0148: Class assignableFromClass = this .classloader
0149: .loadClass(assignableFromClassName);
0150: return clazz.isAssignableFrom(assignableFromClass);
0151: } catch (ClassNotFoundException e) {
0152: log.warn(
0153: "Failed to find class: " + assignableFromClassName,
0154: e);
0155: }
0156: return false;
0157: }
0158:
0159: public abstract String getMessageBundle();
0160:
0161: public abstract boolean isCreateMethod(Method m);
0162:
0163: public abstract boolean isEjbCreateMethod(Method m);
0164:
0165: public boolean hasLegalRMIIIOPArguments(Method method) {
0166: Class[] params = method.getParameterTypes();
0167:
0168: for (int i = 0; i < params.length; ++i) {
0169: if (!isRMIIIOPType(params[i]))
0170: return false;
0171: }
0172:
0173: return true;
0174: }
0175:
0176: public boolean hasLegalRMIIIOPReturnType(Method method) {
0177: return isRMIIIOPType(method.getReturnType());
0178: }
0179:
0180: public boolean hasLegalRMIIIOPExceptionTypes(Method method) {
0181: /*
0182: * All checked exception classes used in method declarations
0183: * (other than java.rmi.RemoteException) MUST be conforming
0184: * RMI/IDL exception types.
0185: *
0186: * Spec 28.2.3 (4)
0187: */
0188: Iterator it = Arrays.asList(method.getExceptionTypes())
0189: .iterator();
0190: while (it.hasNext()) {
0191: Class exception = (Class) it.next();
0192:
0193: if (!isRMIIDLExceptionType(exception))
0194: return false;
0195: }
0196:
0197: return true;
0198: }
0199:
0200: /**
0201: * Checks if the method includes java.rmi.RemoteException or its
0202: * subclass in its throws clause.
0203: *
0204: * See bug report #434739 and #607805
0205: */
0206: public boolean throwsRemoteException(Method method) {
0207: Class[] exception = method.getExceptionTypes();
0208:
0209: for (int i = 0; i < exception.length; ++i) {
0210: // Fix for bug #607805: an IOException is OK for local interfaces
0211: // Fix for bug #626430: java.lang.Exception is also OK
0212: if (exception[i].equals(java.io.IOException.class)
0213: || exception[i].equals(java.lang.Exception.class)) {
0214: continue;
0215: }
0216: // Not true see bug report #434739
0217: // if (java.rmi.RemoteException.class.isAssignableFrom(exception[i]))
0218: // According to the RMI spec. a remote interface must throw an RemoteException
0219: // or any of its super classes therefore the check must be done vice versa
0220:
0221: if (isAssignableFrom(exception[i],
0222: "java.rmi.RemoteException")) {
0223: return true;
0224: }
0225: }
0226:
0227: return false;
0228: }
0229:
0230: /**
0231: * checks if the method accepts a single parameter of a specified type.
0232: */
0233: public boolean hasSingleArgument(Method method, Class argClass) {
0234: Class[] params = method.getParameterTypes();
0235: if (params.length == 1) {
0236: if (params[0].equals(argClass))
0237: return true;
0238: }
0239:
0240: return false;
0241: }
0242:
0243: /**
0244: * checks if the method accepts any parameters.
0245: */
0246: public boolean hasNoArguments(Method method) {
0247: Class[] params = method.getParameterTypes();
0248: return (params.length == 0) ? true : false;
0249: }
0250:
0251: /**
0252: * checks if the method throws no checked exceptions in its throws clause.
0253: */
0254: public boolean throwsNoException(Method method) {
0255: boolean hasCheckedException = false;
0256: Class[] exceptions = method.getExceptionTypes();
0257: for (int e = 0; e < exceptions.length; e++) {
0258: Class ex = exceptions[e];
0259: boolean isError = Error.class.isAssignableFrom(ex);
0260: boolean isRuntimeException = RuntimeException.class
0261: .isAssignableFrom(ex);
0262: boolean isRemoteException = RemoteException.class
0263: .isAssignableFrom(ex);
0264: if (isError == false && isRuntimeException == false
0265: && isRemoteException == false)
0266: hasCheckedException = true;
0267: }
0268: return hasCheckedException == false;
0269: }
0270:
0271: /**
0272: * checks if the method includes java.ejb.CreateException in its
0273: * throws clause.
0274: */
0275: public boolean throwsCreateException(Method method) {
0276: Class[] exception = method.getExceptionTypes();
0277: for (int i = 0; i < exception.length; ++i) {
0278: if (isAssignableFrom("javax.ejb.CreateException",
0279: exception[i]))
0280: return true;
0281: }
0282:
0283: return false;
0284: }
0285:
0286: /**
0287: * checks if the methods includes javax.ejb.FinderException in its
0288: * throws clause.
0289: */
0290: public boolean throwsFinderException(Method method) {
0291: Class[] exception = method.getExceptionTypes();
0292:
0293: for (int i = 0; i < exception.length; ++i) {
0294: if (isAssignableFrom("javax.ejb.FinderException",
0295: exception[i]))
0296: return true;
0297: }
0298:
0299: return false;
0300: }
0301:
0302: /**
0303: * checks if a class's member (method, constructor or field) has a
0304: * <code>static</code> modifier.
0305: */
0306: public boolean isStatic(Member member) {
0307: return (Modifier.isStatic(member.getModifiers()));
0308: }
0309:
0310: /**
0311: * checks if the given class is declared as static (inner classes only)
0312: */
0313: public boolean isStatic(Class c) {
0314: return (Modifier.isStatic(c.getModifiers()));
0315: }
0316:
0317: /**
0318: * checks if a class's member (method, constructor or field) has a
0319: * <code>final</code> modifier.
0320: */
0321: public boolean isFinal(Member member) {
0322: return (Modifier.isFinal(member.getModifiers()));
0323: }
0324:
0325: /**
0326: * checks if the given class is declared as final
0327: */
0328: public boolean isFinal(Class c) {
0329: return (Modifier.isFinal(c.getModifiers()));
0330: }
0331:
0332: /**
0333: * checks if a class's member (method, constructor or field) has a
0334: * <code>public</code> modifier.
0335: */
0336: public boolean isPublic(Member member) {
0337: return (Modifier.isPublic(member.getModifiers()));
0338: }
0339:
0340: /**
0341: * checks if the given class is declared as <code>public</code>
0342: */
0343: public boolean isPublic(Class c) {
0344: return (Modifier.isPublic(c.getModifiers()));
0345: }
0346:
0347: /**
0348: * Checks whether all the fields in the class are declared as public.
0349: */
0350: public boolean isAllFieldsPublic(Class c) {
0351: try {
0352: Field list[] = c.getFields();
0353: for (int i = 0; i < list.length; i++) {
0354: if (!Modifier.isPublic(list[i].getModifiers()))
0355: return false;
0356: }
0357: } catch (Exception e) {
0358: return false;
0359: }
0360:
0361: return true;
0362: }
0363:
0364: /**
0365: * checks if the given class is declared as abstract
0366: */
0367: public boolean isAbstract(Class c) {
0368: return (Modifier.isAbstract(c.getModifiers()));
0369: }
0370:
0371: /**
0372: * checks if the given method is declared as abstract
0373: */
0374: public boolean isAbstract(Method m) {
0375: return (Modifier.isAbstract(m.getModifiers()));
0376: }
0377:
0378: /**
0379: * checks if finder returns the primary key type
0380: */
0381: public boolean isSingleObjectFinder(EntityMetaData entity,
0382: Method finder) {
0383: return hasPrimaryKeyReturnType(entity, finder);
0384: }
0385:
0386: /**
0387: * checks if finder method returns either Collection or Enumeration
0388: */
0389: public boolean isMultiObjectFinder(Method f) {
0390: return (java.util.Collection.class.isAssignableFrom(f
0391: .getReturnType()) || java.util.Enumeration.class
0392: .isAssignableFrom(f.getReturnType()));
0393: }
0394:
0395: /**
0396: * checks the return type of method matches the bean's remote interface
0397: */
0398: public boolean hasRemoteReturnType(BeanMetaData bean, Method m) {
0399: try {
0400: Class clazz = classloader.loadClass(bean.getRemote());
0401: return m.getReturnType().isAssignableFrom(clazz);
0402: } catch (Exception e) {
0403: // e.printStackTrace();
0404: return false;
0405: }
0406: }
0407:
0408: /**
0409: * checks the return type of method matches the bean's local interface
0410: */
0411: public boolean hasLocalReturnType(BeanMetaData bean, Method m) {
0412: try {
0413: Class clazz = classloader.loadClass(bean.getLocal());
0414: return m.getReturnType().isAssignableFrom(clazz);
0415: } catch (Exception e) {
0416: // e.printStackTrace();
0417: return false;
0418: }
0419: }
0420:
0421: /**
0422: * checks if a method has a void return type
0423: */
0424: public boolean hasVoidReturnType(Method method) {
0425: return (method.getReturnType() == Void.TYPE);
0426: }
0427:
0428: /**
0429: * Finds java.ejb.MessageDrivenBean interface from the class
0430: */
0431: public boolean hasMessageDrivenBeanInterface(Class c) {
0432: return isAssignableFrom("javax.ejb.MessageDrivenBean", c);
0433: }
0434:
0435: /**
0436: * Finds javax.jms.MessageListener interface from the class
0437: */
0438: public boolean hasMessageListenerInterface(Class c) {
0439: return isAssignableFrom("javax.jms.MessageListener", c);
0440: }
0441:
0442: /**
0443: * Finds java.ejb.SessionBean interface from the class
0444: */
0445: public boolean hasSessionBeanInterface(Class c) {
0446: return isAssignableFrom("javax.ejb.SessionBean", c);
0447: }
0448:
0449: /**
0450: * Finds java.ejb.EntityBean interface from the class
0451: */
0452: public boolean hasEntityBeanInterface(Class c) {
0453: return isAssignableFrom("javax.ejb.EntityBean", c);
0454: }
0455:
0456: /**
0457: * Finds java.ejb.EJBObject interface from the class
0458: */
0459: public boolean hasEJBObjectInterface(Class c) {
0460: return isAssignableFrom("javax.ejb.EJBObject", c);
0461: }
0462:
0463: /**
0464: * Finds java.ejb.EJBLocalObject interface from the class
0465: */
0466: public boolean hasEJBLocalObjectInterface(Class c) {
0467: return isAssignableFrom("javax.ejb.EJBLocalObject", c);
0468: }
0469:
0470: /**
0471: * Finds javax.ejb.EJBHome interface from the class or its
0472: * superclasses
0473: */
0474: public boolean hasEJBHomeInterface(Class c) {
0475: return isAssignableFrom("javax.ejb.EJBHome", c);
0476: }
0477:
0478: /**
0479: * Finds javax.ejb.EJBLocalHome interface from the class or its
0480: * superclasses
0481: */
0482: public boolean hasEJBLocalHomeInterface(Class c) {
0483: return isAssignableFrom("javax.ejb.EJBLocalHome", c);
0484: }
0485:
0486: /**
0487: * Finds javax.ejb.SessionSynchronization interface from the class
0488: */
0489: public boolean hasSessionSynchronizationInterface(Class c) {
0490: return isAssignableFrom("javax.ejb.SessionSynchronization", c);
0491: }
0492:
0493: /**
0494: * Checks if a class has a default (no args) constructor
0495: */
0496: public boolean hasDefaultConstructor(Class c) {
0497: try {
0498: Constructor ctr = c.getConstructor(new Class[0]);
0499: } catch (NoSuchMethodException e) {
0500: if (log.isTraceEnabled()) {
0501: StringBuffer tmp = new StringBuffer(
0502: "hasDefaultConstructor(");
0503: tmp.append(") failure, ");
0504: Classes.displayClassInfo(c, tmp);
0505: log.trace(tmp.toString(), e);
0506: }
0507: return false;
0508: }
0509:
0510: return true;
0511: }
0512:
0513: /**
0514: * Checks of the class defines a finalize() method
0515: */
0516: public boolean hasFinalizer(Class c) {
0517: try {
0518: Method finalizer = c.getDeclaredMethod(FINALIZE_METHOD,
0519: new Class[0]);
0520: } catch (NoSuchMethodException e) {
0521: return false;
0522: }
0523:
0524: return true;
0525: }
0526:
0527: /**
0528: * check if a class has one or more finder methods
0529: */
0530: public boolean hasFinderMethod(Class c) {
0531: Method[] method = c.getMethods();
0532: for (int i = 0; i < method.length; ++i) {
0533: if (method[i].getName().startsWith("ejbFind"))
0534: return true;
0535: }
0536:
0537: return false;
0538: }
0539:
0540: /**
0541: * Check if this is a finder method
0542: */
0543: public boolean isFinderMethod(Method m) {
0544: return (m.getName().startsWith("find"));
0545: }
0546:
0547: /**
0548: * Check if the given message is the onMessage() method
0549: */
0550: public boolean isOnMessageMethod(Method m) {
0551: if ("onMessage".equals(m.getName())) {
0552: Class[] paramTypes = m.getParameterTypes();
0553: if (paramTypes.length == 1) {
0554: if (Message.class.equals(paramTypes[0]))
0555: return true;
0556: }
0557: }
0558: return false;
0559: }
0560:
0561: /**
0562: * Checks for at least one non-static field.
0563: */
0564: public boolean hasANonStaticField(Class c) {
0565: try {
0566: Field list[] = c.getFields();
0567: for (int i = 0; i < list.length; i++) {
0568: if (!Modifier.isStatic(list[i].getModifiers()))
0569: return true;
0570: }
0571: } catch (Exception ignored) {
0572: }
0573:
0574: return false;
0575: }
0576:
0577: /**
0578: * Searches for an instance of a public onMessage method from the class
0579: */
0580: public boolean hasOnMessageMethod(Class c) {
0581: Method[] method = c.getMethods();
0582: for (int i = 0; i < method.length; ++i) {
0583: if (isOnMessageMethod(method[i]))
0584: return true;
0585: }
0586:
0587: return false;
0588: }
0589:
0590: /**
0591: * Searches for an instance of a public create method from the class
0592: */
0593: public boolean hasCreateMethod(Class c) {
0594: Method[] method = c.getMethods();
0595:
0596: for (int i = 0; i < method.length; ++i) {
0597: if (isCreateMethod(method[i]))
0598: return true;
0599: }
0600:
0601: return false;
0602: }
0603:
0604: /**
0605: * Searches for an instance of a public ejbCreate method from the class
0606: */
0607: public boolean hasEJBCreateMethod(Class c, boolean isSession) {
0608: Method[] method = c.getMethods();
0609: for (int i = 0; i < method.length; ++i) {
0610: if (isEjbCreateMethod(method[i])) {
0611: if (!isStatic(method[i])
0612: && !isFinal(method[i])
0613: && ((isSession && hasVoidReturnType(method[i])) || (!isSession))) {
0614: return true;
0615: }
0616: }
0617: }
0618:
0619: return false;
0620: }
0621:
0622: /**
0623: * Searches the class or interface, and its superclass or superinterface
0624: * for a create() method that takes no arguments
0625: */
0626: public boolean hasDefaultCreateMethod(Class home) {
0627: Method[] method = home.getMethods();
0628:
0629: for (int i = 0; i < method.length; ++i) {
0630: if (isCreateMethod(method[i])) {
0631: Class[] params = method[i].getParameterTypes();
0632: if (params.length == 0)
0633: return true;
0634: }
0635: }
0636:
0637: return false;
0638: }
0639:
0640: /**
0641: * checks if the class has an ejbFindByPrimaryKey method
0642: */
0643: public boolean hasEJBFindByPrimaryKey(Class c) {
0644: Method[] method = c.getMethods();
0645: for (int i = 0; i < method.length; ++i) {
0646: if (method[i].getName().equals(EJB_FIND_BY_PRIMARY_KEY))
0647: return true;
0648: }
0649:
0650: return false;
0651: }
0652:
0653: /**
0654: * checks the return type of method matches the entity's primary key
0655: * class or is a super class of the primary key class
0656: */
0657: public boolean hasPrimaryKeyReturnType(EntityMetaData entity,
0658: Method m) {
0659: try {
0660: return m.getReturnType().isAssignableFrom(
0661: classloader.loadClass(entity.getPrimaryKeyClass()));
0662: } catch (ClassNotFoundException cnfe) {
0663: // Only check equality
0664: return m.getReturnType().getName().equals(
0665: entity.getPrimaryKeyClass());
0666: }
0667: }
0668:
0669: /**
0670: * @return Returns the default create method or <code>null</code>
0671: * if none is found
0672: */
0673: public Method getDefaultCreateMethod(Class c) {
0674: Method method = null;
0675:
0676: try {
0677: method = c.getMethod(CREATE_METHOD, null);
0678: } catch (NoSuchMethodException ignored) {
0679: }
0680:
0681: return method;
0682: }
0683:
0684: /**
0685: * Returns the ejbFindByPrimaryKey method
0686: */
0687: public Method getEJBFindByPrimaryKey(Class c) {
0688: Method[] method = c.getMethods();
0689: for (int i = 0; i < method.length; ++i) {
0690: if (method[i].getName().equals(EJB_FIND_BY_PRIMARY_KEY))
0691: return method[i];
0692: }
0693:
0694: return null;
0695: }
0696:
0697: /**
0698: * returns the ejbFind<METHOD> methods of a bean
0699: */
0700: public Iterator getEJBFindMethods(Class c) {
0701: List finders = new LinkedList();
0702: Method[] method = c.getMethods();
0703: for (int i = 0; i < method.length; ++i) {
0704: if (method[i].getName().startsWith("ejbFind"))
0705: finders.add(method[i]);
0706: }
0707:
0708: return finders.iterator();
0709: }
0710:
0711: /**
0712: * returns the finder methods of a home interface
0713: */
0714: public Iterator getFinderMethods(Class home) {
0715: List finders = new LinkedList();
0716: Method[] method = home.getMethods();
0717:
0718: for (int i = 0; i < method.length; ++i) {
0719: if (method[i].getName().startsWith("find"))
0720: finders.add(method[i]);
0721: }
0722:
0723: return finders.iterator();
0724: }
0725:
0726: /**
0727: * Returns the onMessage(...) method of a bean
0728: */
0729: public Iterator getOnMessageMethods(Class c) {
0730: List onMessages = new LinkedList();
0731: Method[] method = c.getMethods();
0732:
0733: for (int i = 0; i < method.length; ++i) {
0734: if (isOnMessageMethod(method[i]))
0735: onMessages.add(method[i]);
0736: }
0737:
0738: return onMessages.iterator();
0739: }
0740:
0741: /**
0742: * Returns the ejbCreate(...) methods of a bean
0743: */
0744: public Iterator getEJBCreateMethods(Class c) {
0745: List ejbCreates = new LinkedList();
0746: Method[] method = c.getMethods();
0747:
0748: for (int i = 0; i < method.length; ++i) {
0749: if (isEjbCreateMethod(method[i]))
0750: ejbCreates.add(method[i]);
0751: }
0752:
0753: return ejbCreates.iterator();
0754: }
0755:
0756: /**
0757: * Return all create methods of a class
0758: */
0759: public Iterator getCreateMethods(Class c) {
0760: List creates = new LinkedList();
0761: Method[] method = c.getMethods();
0762:
0763: for (int i = 0; i < method.length; ++i) {
0764: if (isCreateMethod(method[i]))
0765: creates.add(method[i]);
0766: }
0767:
0768: return creates.iterator();
0769: }
0770:
0771: /**
0772: * Check whether a class has more than one create method
0773: */
0774: public boolean hasMoreThanOneCreateMethods(Class c) {
0775: int count = 0;
0776: Method[] method = c.getMethods();
0777: for (int i = 0; i < method.length; ++i) {
0778: if (isCreateMethod(method[i])) {
0779: ++count;
0780: }
0781: }
0782:
0783: return (count > 1);
0784: }
0785:
0786: /**
0787: * Check whether two given methods declare the same Exceptions
0788: */
0789: public boolean hasMatchingExceptions(Method source, Method target) {
0790: // target must be a superset of source
0791: Class[] a = source.getExceptionTypes();
0792: Class[] b = target.getExceptionTypes();
0793: Class rteClass = null;
0794: Class errorClass = null;
0795:
0796: try {
0797: rteClass = classloader
0798: .loadClass("java.lang.RuntimeException");
0799: errorClass = classloader.loadClass("java.lang.Error");
0800: } catch (ClassNotFoundException cnfe) {
0801: // Ignored, if this happens we have more serious problems :)
0802: }
0803:
0804: for (int i = 0; i < a.length; ++i) {
0805: if (rteClass.isAssignableFrom(a[i])
0806: || errorClass.isAssignableFrom(a[i])) {
0807: // Skip over subclasses of java.lang.RuntimeException and
0808: // java.lang.Error
0809: continue;
0810: }
0811:
0812: boolean found = false;
0813: for (int j = 0; j < b.length; ++j) {
0814: if (b[j].isAssignableFrom(a[i])) {
0815: found = true;
0816: break;
0817: }
0818: }
0819:
0820: if (!found) {
0821: return false;
0822: }
0823: }
0824:
0825: return true;
0826: }
0827:
0828: /**
0829: * Check if a class (or its superclasses) declare a given method
0830: */
0831: public boolean hasMatchingMethod(Class bean, Method method) {
0832: try {
0833: bean
0834: .getMethod(method.getName(), method
0835: .getParameterTypes());
0836: return true;
0837: } catch (NoSuchMethodException e) {
0838: if (log.isTraceEnabled()) {
0839: StringBuffer tmp = new StringBuffer(
0840: "hasMatchingMethod(");
0841: tmp.append(method.toString());
0842: tmp.append(") failure, ");
0843: Classes.displayClassInfo(bean, tmp);
0844: log.trace(tmp.toString(), e);
0845: }
0846: return false;
0847: }
0848: }
0849:
0850: /**
0851: * Check whether two methods have the same return type
0852: */
0853: public boolean hasMatchingReturnType(Method a, Method b) {
0854: return (a.getReturnType() == b.getReturnType());
0855: }
0856:
0857: /**
0858: * Check whether a bean has a matching ejbPostCreate methods for
0859: * a given ejbCreate method
0860: */
0861: public boolean hasMatchingEJBPostCreate(Class bean, Method create) {
0862: try {
0863: return (bean.getMethod(getMatchingEJBPostCreateName(create
0864: .getName()), create.getParameterTypes()) != null);
0865: } catch (NoSuchMethodException e) {
0866: if (log.isTraceEnabled()) {
0867: StringBuffer tmp = new StringBuffer(
0868: "hasMatchingEJBPostCreate(");
0869: tmp.append(create.toString());
0870: tmp.append(") failure, ");
0871: Classes.displayClassInfo(bean, tmp);
0872: log.trace(tmp.toString(), e);
0873: }
0874: return false;
0875: }
0876: }
0877:
0878: public boolean hasMatchingEJBCreate(Class bean, Method create) {
0879: try {
0880: return (bean.getMethod(getMatchingEJBCreateName(create
0881: .getName()), create.getParameterTypes()) != null);
0882: } catch (NoSuchMethodException e) {
0883: if (log.isTraceEnabled()) {
0884: StringBuffer tmp = new StringBuffer(
0885: "hasMatchingEJBCreate(");
0886: tmp.append(create.toString());
0887: tmp.append(") failure, ");
0888: Classes.displayClassInfo(bean, tmp);
0889: log.trace(tmp.toString(), e);
0890: }
0891: return false;
0892: }
0893: }
0894:
0895: public Method getMatchingEJBPostCreate(Class bean, Method create) {
0896: try {
0897: return bean.getMethod(getMatchingEJBPostCreateName(create
0898: .getName()), create.getParameterTypes());
0899: } catch (NoSuchMethodException e) {
0900: return null;
0901: }
0902: }
0903:
0904: public Method getMatchingEJBCreate(Class bean, Method create) {
0905: try {
0906: return bean.getMethod(getMatchingEJBCreateName(create
0907: .getName()), create.getParameterTypes());
0908: } catch (NoSuchMethodException e) {
0909: return null;
0910: }
0911: }
0912:
0913: public boolean hasMatchingEJBFind(Class bean, Method finder) {
0914: try {
0915: String methodName = "ejbF" + finder.getName().substring(1);
0916: return (bean.getMethod(methodName, finder
0917: .getParameterTypes()) != null);
0918: } catch (NoSuchMethodException e) {
0919: if (log.isTraceEnabled()) {
0920: StringBuffer tmp = new StringBuffer(
0921: "hasMatchingEJBFind(");
0922: tmp.append(finder.toString());
0923: tmp.append(") failure, ");
0924: Classes.displayClassInfo(bean, tmp);
0925: log.trace(tmp.toString(), e);
0926: }
0927: return false;
0928: }
0929: }
0930:
0931: public Method getMatchingEJBFind(Class bean, Method finder) {
0932: try {
0933: String methodName = "ejbF" + finder.getName().substring(1);
0934: return bean.getMethod(methodName, finder
0935: .getParameterTypes());
0936: } catch (NoSuchMethodException e) {
0937: return null;
0938: }
0939: }
0940:
0941: public boolean hasMatchingEJBHome(Class bean, Method home) {
0942: try {
0943: return (bean.getMethod(getMatchingEJBHomeName(home
0944: .getName()), home.getParameterTypes()) != null);
0945: } catch (NoSuchMethodException e) {
0946: if (log.isTraceEnabled()) {
0947: StringBuffer tmp = new StringBuffer(
0948: "hasMatchingEJBHome(");
0949: tmp.append(home.toString());
0950: tmp.append(") failure, ");
0951: Classes.displayClassInfo(bean, tmp);
0952: log.trace(tmp.toString(), e);
0953: }
0954: return false;
0955: }
0956: }
0957:
0958: /*
0959: *************************************************************************
0960: *
0961: * PROTECTED INSTANCE METHODS
0962: *
0963: *************************************************************************
0964: */
0965:
0966: protected void fireSpecViolationEvent(BeanMetaData bean,
0967: Section section) {
0968: fireSpecViolationEvent(bean, null /* method */, section);
0969: }
0970:
0971: protected void fireSpecViolationEvent(BeanMetaData bean,
0972: Method method, Section section) {
0973: VerificationEvent event = factory.createSpecViolationEvent(
0974: context, section);
0975: event.setName(bean.getEjbName());
0976: event.setMethod(method);
0977:
0978: context.fireSpecViolation(event);
0979: }
0980:
0981: protected final void fireBeanVerifiedEvent(BeanMetaData bean) {
0982: fireBeanVerifiedEvent(bean, null);
0983: }
0984:
0985: protected final void fireBeanVerifiedEvent(BeanMetaData bean,
0986: String msg) {
0987: VerificationEvent event = factory
0988: .createBeanVerifiedEvent(context);
0989: event.setName(bean.getEjbName());
0990:
0991: if (msg != null) {
0992: event.setMessage(msg);
0993: }
0994:
0995: context.fireBeanChecked(event);
0996: }
0997:
0998: /*
0999: *************************************************************************
1000: *
1001: * IMPLEMENTS VERIFICATIONSTRATEGY INTERFACE
1002: *
1003: *************************************************************************
1004: */
1005:
1006: /**
1007: * Provides an empty default implementation for EJB 1.1 verifier (message
1008: * beans are for EJB 2.0 and greater only).
1009: *
1010: * @param bean the message bean to verify
1011: */
1012: public void checkMessageBean(MessageDrivenMetaData bean) {
1013: }
1014:
1015: /**
1016: * Returns the context object reference for this strategy implementation.
1017: *
1018: * @return the client object using this algorithm implementation
1019: */
1020: public StrategyContext getContext() {
1021: return context;
1022: }
1023:
1024: /*
1025: *************************************************************************
1026: *
1027: * PRIVATE INSTANCE METHODS
1028: *
1029: *************************************************************************
1030: */
1031:
1032: protected boolean isRMIIIOPType(Class type) {
1033: /*
1034: * Java Language to IDL Mapping
1035: *
1036: * ftp://ftp.omg.org/pub/docs/ptc/99-03-09.pdf
1037: *
1038: * A conforming RMI/IDL type is a Java type whose values may be
1039: * transmitted across an RMI/IDL remote interface at run-time.
1040: * A Java data type is a conforming RMI/IDL type if it is:
1041: *
1042: * - one of the Java primitive types (see Primitive Types on
1043: * page 28-2).
1044: * - a conforming remote interface (as defined in RMI/IDL
1045: * Remote Interfaces on page 28-2).
1046: * - a conforming value type (as defined in RMI/IDL Value Types
1047: * on page 28-4).
1048: * - an array of conforming RMI/IDL types (see RMI/IDL Arrays on
1049: * page 28-5).
1050: * - a conforming exception type (see RMI/IDL Exception Types on
1051: * page 28-5).
1052: * - a conforming CORBA object reference type (see CORBA Object
1053: * Reference Types on page 28-6).
1054: * - a conforming IDL entity type see IDL Entity Types on page
1055: * 28-6).
1056: */
1057:
1058: /*
1059: * Primitive types.
1060: *
1061: * Spec 28.2.2
1062: */
1063: if (type.isPrimitive())
1064: return true;
1065:
1066: /*
1067: * Conforming array.
1068: *
1069: * Spec 28.2.5
1070: */
1071: if (type.isArray())
1072: return isRMIIIOPType(type.getComponentType());
1073:
1074: /*
1075: * Conforming CORBA reference type
1076: *
1077: * Spec 28.2.7
1078: */
1079: if (org.omg.CORBA.Object.class.isAssignableFrom(type))
1080: return true;
1081:
1082: /*
1083: * Conforming IDL Entity type
1084: *
1085: * Spec 28.2.8
1086: */
1087: if (org.omg.CORBA.portable.IDLEntity.class
1088: .isAssignableFrom(type))
1089: return true;
1090:
1091: /*
1092: * Conforming remote interface.
1093: *
1094: * Spec 28.2.3
1095: */
1096: if (isRMIIDLRemoteInterface(type))
1097: return true;
1098:
1099: /*
1100: * Conforming exception.
1101: *
1102: * Spec 28.2.6
1103: */
1104: if (isRMIIDLExceptionType(type))
1105: return true;
1106:
1107: /*
1108: * Conforming value type.
1109: *
1110: * Spec 28.2.4
1111: */
1112: if (isRMIIDLValueType(type))
1113: return true;
1114:
1115: return false;
1116: }
1117:
1118: private boolean isRMIIDLRemoteInterface(Class type) {
1119: /*
1120: * If does not implement java.rmi.Remote, cannot be valid RMI-IDL
1121: * remote interface.
1122: */
1123:
1124: if (!java.rmi.Remote.class.isAssignableFrom(type))
1125: return false;
1126:
1127: Iterator methodIterator = Arrays.asList(type.getMethods())
1128: .iterator();
1129: while (methodIterator.hasNext()) {
1130: Method m = (Method) methodIterator.next();
1131:
1132: /*
1133: * All methods in the interface MUST throw
1134: * java.rmi.RemoteException or its subclass.
1135: *
1136: * Spec 28.2.3 (2)
1137: */
1138: if (!throwsRemoteException(m))
1139: return false;
1140:
1141: /*
1142: * All checked exception classes used in method declarations
1143: * (other than java.rmi.RemoteException) MUST be conforming
1144: * RMI/IDL exception types.
1145: *
1146: * Spec 28.2.3 (4)
1147: */
1148: Iterator it = Arrays.asList(m.getExceptionTypes())
1149: .iterator();
1150: while (it.hasNext()) {
1151: Class exception = (Class) it.next();
1152: if (!isRMIIDLExceptionType(exception))
1153: return false;
1154: }
1155: }
1156:
1157: /*
1158: * The constant values defined in the interface MUST be
1159: * compile-time types of RMI/IDL primitive types or String.
1160: *
1161: * Spec 28.2.3 (6)
1162: */
1163: Iterator fieldIterator = Arrays.asList(type.getFields())
1164: .iterator();
1165: while (fieldIterator.hasNext()) {
1166: Field f = (Field) fieldIterator.next();
1167:
1168: if (f.getType().isPrimitive())
1169: continue;
1170:
1171: if (f.getType().equals(java.lang.String.class))
1172: continue;
1173:
1174: return false;
1175: }
1176:
1177: return true;
1178: }
1179:
1180: private boolean isRMIIDLExceptionType(Class type) {
1181: /*
1182: * A conforming RMI/IDL Exception class MUST be a checked
1183: * exception class and MUST be a valid RMI/IDL value type.
1184: *
1185: * Spec 28.2.6
1186: */
1187: if (!Throwable.class.isAssignableFrom(type))
1188: return false;
1189:
1190: if (Error.class.isAssignableFrom(type))
1191: return false;
1192:
1193: // 28.3.4.4 (6) java.rmi.RemoteException and its subclasses, and unchecked
1194: // exception classes, are assumed to be mapped to the implicit
1195: // CORBA system exception, and are therefore not explicitly
1196: // declared in OMG IDL.
1197: //
1198: // if (RuntimeException.class.isAssignableFrom(type))
1199: // return false;
1200:
1201: if (!isRMIIDLValueType(type))
1202: return false;
1203:
1204: return true;
1205: }
1206:
1207: protected boolean isRMIIDLValueType(Class type) {
1208: /*
1209: * A value type MUST NOT either directly or indirectly implement the
1210: * java.rmi.Remote interface.
1211: *
1212: * Spec 28.2.4 (4)
1213: */
1214: if (java.rmi.Remote.class.isAssignableFrom(type))
1215: return false;
1216:
1217: /*
1218: * If class is a non-static inner class then its containing class must
1219: * also be a conforming RMI/IDL value type.
1220: *
1221: * Spec 28.2.4 (3)
1222: */
1223: if (type.getDeclaringClass() != null && !isStatic(type)) {
1224: if (!isRMIIDLValueType(type.getDeclaringClass()))
1225: return false;
1226: }
1227:
1228: return true;
1229: }
1230:
1231: private String getMatchingEJBHomeName(String homeName) {
1232: return "ejbHome" + homeName.substring(0, 1).toUpperCase()
1233: + homeName.substring(1);
1234: }
1235:
1236: private String getMatchingEJBCreateName(String createName) {
1237: return "ejb" + createName.substring(0, 1).toUpperCase()
1238: + createName.substring(1);
1239: }
1240:
1241: private String getMatchingEJBPostCreateName(String createName) {
1242: int createIdx = createName.indexOf("Create");
1243: return "ejbPost"
1244: + createName.substring(createIdx >= 0 ? createIdx : 0);
1245: }
1246:
1247: /*
1248: *************************************************************************
1249: *
1250: * STRING CONSTANTS
1251: *
1252: *************************************************************************
1253: */
1254:
1255: /*
1256: * Ejb-jar DTD
1257: */
1258: public final static String BEAN_MANAGED_TX = "Bean";
1259:
1260: public final static String CONTAINER_MANAGED_TX = "Container";
1261:
1262: public final static String STATEFUL_SESSION = "Stateful";
1263:
1264: public final static String STATELESS_SESSION = "Stateless";
1265:
1266: /*
1267: * method names
1268: */
1269: private final static String EJB_FIND_BY_PRIMARY_KEY = "ejbFindByPrimaryKey";
1270:
1271: protected final static String EJB_CREATE_METHOD = "ejbCreate";
1272:
1273: protected final static String EJB_REMOVE_METHOD = "ejbRemove";
1274:
1275: private final static String EJB_POST_CREATE_METHOD = "ejbPostCreate";
1276:
1277: protected final static String CREATE_METHOD = "create";
1278:
1279: protected final static String EJB_HOME_METHOD = "ejbHome";
1280:
1281: protected final static String EJB_SELECT_METHOD = "ejbSelect";
1282:
1283: private final static String FINALIZE_METHOD = "finalize";
1284:
1285: private final static String REMOVE_METHOD = "remove";
1286:
1287: private final static String GET_HOME_HANDLE_METHOD = "getHomeHandle";
1288:
1289: private final static String GET_EJB_METADATA_METHOD = "getEJBMetaData";
1290: }
1291:
1292: /*
1293: vim:ts=3:sw=3:et
1294: */
|