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: // $Id: EJBVerifier11.java 57209 2006-09-26 12:21:57Z dimitris@jboss.org $
0025:
0026: import org.jboss.metadata.EntityMetaData;
0027: import org.jboss.metadata.SessionMetaData;
0028: import org.jboss.verifier.Section;
0029:
0030: import java.lang.reflect.Field;
0031: import java.lang.reflect.Method;
0032: import java.util.Arrays;
0033: import java.util.Iterator;
0034:
0035: /**
0036: * Concrete implementation of the <code>VerificationStrategy</code> interface.
0037: * This class implements the verification of both session and entity beans for
0038: * Enterprise JavaBeans v1.1 specification.
0039: *
0040: * For more detailed documentation, refer to the
0041: * <a href="http://java.sun.com/products/ejb/docs.html">Enterprise JavaBeans v1.1, Final Release</a>
0042: *
0043: * @see org.jboss.verifier.strategy.AbstractVerifier
0044: *
0045: * @author <a href="mailto:juha.lindfors@jboss.org">Juha Lindfors</a>
0046: * @author Aaron Mulder (ammulder@alumni.princeton.edu)
0047: * @author Vinay Menon (menonv@cpw.co.uk)
0048: * @author Thomas.Diesler@jboss.org
0049: *
0050: * @version $Revision: 57209 $
0051: * @since JDK 1.3
0052: */
0053: public class EJBVerifier11 extends AbstractVerifier {
0054:
0055: /**
0056: * Constructs the verifier object.
0057: *
0058: * @param context context for application information
0059: */
0060: public EJBVerifier11(VerificationContext context) {
0061: super (context);
0062: }
0063:
0064: public String getMessageBundle() {
0065: return "EJB11Messages.properties";
0066: }
0067:
0068: /***********************************************************************
0069: *
0070: * IMPLEMENTS VERIFICATION STRATEGY INTERFACE
0071: *
0072: ************************************************************************/
0073:
0074: /**
0075: * Verifies the session bean class, home interface and remote interface
0076: * against the EJB 1.1 specification.
0077: *
0078: * @param session XML metadata of the session bean
0079: */
0080: public void checkSession(SessionMetaData session) {
0081: boolean beanVerified = false;
0082: boolean homeVerified = false;
0083: boolean remoteVerified = false;
0084:
0085: beanVerified = verifySessionBean(session);
0086: homeVerified = verifySessionHome(session);
0087: remoteVerified = verifySessionRemote(session);
0088:
0089: if (beanVerified && homeVerified && remoteVerified) {
0090: /*
0091: * Verification for this session bean done. Fire the event
0092: * to tell listeneres everything is ok.
0093: */
0094: fireBeanVerifiedEvent(session);
0095: }
0096: }
0097:
0098: /**
0099: * Verifies the entity bean class, home interface, remote interface and
0100: * primary key class against the EJB 1.1 specification.
0101: *
0102: * @param entity XML metadata of the session bean
0103: */
0104: public void checkEntity(EntityMetaData entity) {
0105: boolean pkVerified = false;
0106: boolean beanVerified = false;
0107: boolean homeVerified = false;
0108: boolean remoteVerified = false;
0109:
0110: beanVerified = verifyEntityBean(entity);
0111: homeVerified = verifyEntityHome(entity);
0112: remoteVerified = verifyEntityRemote(entity);
0113: pkVerified = verifyPrimaryKey(entity);
0114:
0115: if (beanVerified && homeVerified && remoteVerified
0116: && pkVerified) {
0117: /*
0118: * Verification for this entity bean done. Fire the event
0119: * to tell listeneres everything is ok.
0120: */
0121: fireBeanVerifiedEvent(entity);
0122: }
0123: }
0124:
0125: public boolean isCreateMethod(Method m) {
0126: return m.getName().equals(CREATE_METHOD);
0127: }
0128:
0129: public boolean isEjbCreateMethod(Method m) {
0130: return m.getName().equals(EJB_CREATE_METHOD);
0131: }
0132:
0133: /*
0134: *****************************************************************************
0135: *
0136: * VERIFY SESSION BEAN HOME INTERFACE
0137: *
0138: *****************************************************************************
0139: */
0140:
0141: /**
0142: * Verifies the session bean home interface against the EJB 1.1
0143: * specification.
0144: *
0145: * @param session XML metadata of the session bean
0146: */
0147: private boolean verifySessionHome(SessionMetaData session) {
0148: /*
0149: * Indicates whether we issued warnings or not during verification.
0150: * This boolean is returned to the caller.
0151: */
0152: boolean status = true;
0153:
0154: String name = session.getHome();
0155: if (name == null)
0156: return false;
0157:
0158: try {
0159: Class home = classloader.loadClass(name);
0160:
0161: /*
0162: * The home interface of a stateless session bean MUST have one
0163: * create() method that takes no arguments.
0164: *
0165: * The create() method MUST return the session bean's remote
0166: * interface.
0167: *
0168: * There CAN NOT be other create() methods in the home interface.
0169: *
0170: * Spec 6.8
0171: */
0172: if (session.isStateless()) {
0173: if (!hasDefaultCreateMethod(home)) {
0174: fireSpecViolationEvent(session,
0175: new Section("6.8.a"));
0176: status = false;
0177: } else {
0178: Method create = getDefaultCreateMethod(home);
0179:
0180: if (!hasRemoteReturnType(session, create)) {
0181: fireSpecViolationEvent(session, create,
0182: new Section("6.8.b"));
0183: ;
0184: status = false;
0185: }
0186:
0187: if (hasMoreThanOneCreateMethods(home)) {
0188: fireSpecViolationEvent(session, new Section(
0189: "6.8.c"));
0190: status = false;
0191: }
0192: }
0193: }
0194:
0195: /*
0196: * The session bean's home interface MUST extend the
0197: * javax.ejb.EJBHome interface.
0198: *
0199: * Spec 6.10.6
0200: */
0201: if (!hasEJBHomeInterface(home)) {
0202: fireSpecViolationEvent(session, new Section("6.10.6.a"));
0203: status = false;
0204: }
0205:
0206: /*
0207: * Method arguments defined in the home interface MUST be
0208: * of valid types for RMI/IIOP.
0209: *
0210: * Method return values defined in the home interface MUST
0211: * be of valid types for RMI/IIOP.
0212: *
0213: * Methods defined in the home interface MUST include
0214: * java.rmi.RemoteException in their throws clause.
0215: *
0216: * Spec 6.10.6
0217: */
0218: Iterator it = Arrays.asList(home.getMethods()).iterator();
0219: while (it.hasNext()) {
0220: Method method = (Method) it.next();
0221:
0222: if (!hasLegalRMIIIOPArguments(method)) {
0223: fireSpecViolationEvent(session, method,
0224: new Section("6.10.6.b"));
0225: status = false;
0226: }
0227:
0228: if (!hasLegalRMIIIOPReturnType(method)) {
0229: fireSpecViolationEvent(session, method,
0230: new Section("6.10.6.c"));
0231: status = false;
0232: }
0233:
0234: if (!throwsRemoteException(method)) {
0235: fireSpecViolationEvent(session, method,
0236: new Section("6.10.6.d"));
0237: status = false;
0238: }
0239: }
0240:
0241: /*
0242: * A session bean's home interface MUST define one or more
0243: * create(...) methods.
0244: *
0245: * Spec 6.10.6
0246: */
0247: if (!hasCreateMethod(home)) {
0248: fireSpecViolationEvent(session, new Section("6.10.6.e"));
0249: status = false;
0250: }
0251:
0252: /*
0253: * Each create(...) method in the session bean's home interface MUST
0254: * have a matching ejbCreate(...) method in the session bean's class.
0255: *
0256: * Each create(...) method in the session bean's home interface MUST
0257: * have the same number and types of arguments to its matching
0258: * ejbCreate(...) method.
0259: *
0260: * The return type for a create(...) method MUST be the session
0261: * bean's remote interface type.
0262: *
0263: * All the exceptions defined in the throws clause of the matching
0264: * ejbCreate(...) method of the enterprise bean class MUST be
0265: * included in the throws clause of a matching create(...) method.
0266: *
0267: * The throws clause of a create(...) method MUST include the
0268: * javax.ejb.CreateException.
0269: *
0270: * Spec 6.10.6
0271: */
0272: Iterator createMethods = getCreateMethods(home);
0273: try {
0274: String beanClass = session.getEjbClass();
0275: Class bean = classloader.loadClass(beanClass);
0276:
0277: while (createMethods.hasNext()) {
0278: Method create = (Method) createMethods.next();
0279:
0280: if (!hasMatchingEJBCreate(bean, create)) {
0281: fireSpecViolationEvent(session, create,
0282: new Section("6.10.6.f"));
0283: status = false;
0284: }
0285:
0286: if (!hasRemoteReturnType(session, create)) {
0287: fireSpecViolationEvent(session, create,
0288: new Section("6.10.6.g"));
0289: status = false;
0290: }
0291:
0292: if (hasMatchingEJBCreate(bean, create)) {
0293: Method ejbCreate = getMatchingEJBCreate(bean,
0294: create);
0295:
0296: if (!hasMatchingExceptions(ejbCreate, create)) {
0297: fireSpecViolationEvent(session, create,
0298: new Section("6.10.6.h"));
0299: status = false;
0300: }
0301: }
0302:
0303: if (!throwsCreateException(create)) {
0304: fireSpecViolationEvent(session, create,
0305: new Section("6.10.6.i"));
0306: status = false;
0307: }
0308: }
0309: } catch (ClassNotFoundException ignored) {
0310: }
0311: } catch (ClassNotFoundException e) {
0312: /*
0313: * The bean provider MUST specify the fully-qualified name of the
0314: * enterprise bean's home interface in the <home> element.
0315: *
0316: * Spec 16.2
0317: */
0318: fireSpecViolationEvent(session, new Section("16.2.c"));
0319: status = false;
0320: }
0321:
0322: return status;
0323: }
0324:
0325: /*
0326: *************************************************************************
0327: *
0328: * VERIFY SESSION BEAN REMOTE INTERFACE
0329: *
0330: *************************************************************************
0331: */
0332: private boolean verifySessionRemote(SessionMetaData session) {
0333: /*
0334: * Indicates whether we issued warnings or not during verification.
0335: * This boolean is returned to the caller.
0336: */
0337: boolean status = true;
0338:
0339: String name = session.getRemote();
0340: if (name == null)
0341: return false;
0342:
0343: try {
0344: Class remote = classloader.loadClass(name);
0345:
0346: /*
0347: * The remote interface MUST extend the javax.ejb.EJBObject
0348: * interface.
0349: *
0350: * Spec 6.10.5
0351: */
0352: if (!hasEJBObjectInterface(remote)) {
0353: fireSpecViolationEvent(session, new Section("6.10.5.a"));
0354: status = false;
0355: }
0356:
0357: /*
0358: * Method arguments defined in the remote interface MUST be
0359: * of valid types for RMI/IIOP.
0360: *
0361: * Method return values defined in the remote interface MUST
0362: * be of valid types for RMI/IIOP.
0363: *
0364: * Methods defined in the remote interface MUST include
0365: * java.rmi.RemoteException in their throws clause.
0366: *
0367: * Spec 6.10.5
0368: */
0369: Iterator it = Arrays.asList(remote.getMethods()).iterator();
0370: while (it.hasNext()) {
0371: Method method = (Method) it.next();
0372:
0373: if (!hasLegalRMIIIOPArguments(method)) {
0374: fireSpecViolationEvent(session, method,
0375: new Section("6.10.5.b"));
0376: status = false;
0377: }
0378:
0379: if (!hasLegalRMIIIOPReturnType(method)) {
0380: fireSpecViolationEvent(session, method,
0381: new Section("6.10.5.c"));
0382: status = false;
0383: }
0384:
0385: if (!throwsRemoteException(method)) {
0386: fireSpecViolationEvent(session, method,
0387: new Section("6.10.5.d"));
0388: status = false;
0389: }
0390: }
0391:
0392: /*
0393: * For each method defined in the remote interface, there MUST be
0394: * a matching method in the session bean's class. The matching
0395: * method MUST have:
0396: *
0397: * - the same name
0398: * - the same number and types of arguments, and the same
0399: * return type
0400: * - All the exceptions defined in the throws clause of the
0401: * matching method of the session bean class must be defined
0402: * in the throws clause of the method of the remote interface
0403: *
0404: * Spec 6.10.5
0405: */
0406: String beanName = session.getEjbClass();
0407: Class bean = classloader.loadClass(beanName);
0408:
0409: Iterator iterator = Arrays.asList(
0410: remote.getDeclaredMethods()).iterator();
0411: while (iterator.hasNext()) {
0412: Method remoteMethod = (Method) iterator.next();
0413:
0414: if (!hasMatchingMethod(bean, remoteMethod)) {
0415: fireSpecViolationEvent(session, remoteMethod,
0416: new Section("6.10.5.e"));
0417: status = false;
0418: }
0419:
0420: if (hasMatchingMethod(bean, remoteMethod)) {
0421: try {
0422: Method beanMethod = bean.getMethod(remoteMethod
0423: .getName(), remoteMethod
0424: .getParameterTypes());
0425:
0426: if (!hasMatchingReturnType(remoteMethod,
0427: beanMethod)) {
0428: fireSpecViolationEvent(session,
0429: remoteMethod, new Section(
0430: "6.10.5.f"));
0431: status = false;
0432: }
0433:
0434: if (!hasMatchingExceptions(beanMethod,
0435: remoteMethod)) {
0436: fireSpecViolationEvent(session,
0437: remoteMethod, new Section(
0438: "6.10.5.g"));
0439: status = false;
0440: }
0441: } catch (NoSuchMethodException ignored) {
0442: }
0443: }
0444: } // while
0445: } catch (ClassNotFoundException e) {
0446: /*
0447: * The Bean Provider MUST specify the fully-qualified name of the
0448: * enterprise bean's remote interface in the <remote> element.
0449: *
0450: * Spec 16.2
0451: */
0452: fireSpecViolationEvent(session, new Section("16.2.d"));
0453: status = false;
0454: }
0455:
0456: return status;
0457: }
0458:
0459: /*
0460: *************************************************************************
0461: *
0462: * VERIFY SESSION BEAN CLASS
0463: *
0464: *************************************************************************
0465: */
0466: private boolean verifySessionBean(SessionMetaData session) {
0467: boolean status = true;
0468:
0469: String name = session.getEjbClass();
0470:
0471: try {
0472: Class bean = classloader.loadClass(name);
0473:
0474: /*
0475: * A session bean MUST implement, directly or indirectly,
0476: * javax.ejb.SessionBean interface.
0477: *
0478: * Spec 6.5.1
0479: * Spec 6.10.2
0480: */
0481: if (!hasSessionBeanInterface(bean)) {
0482: fireSpecViolationEvent(session, new Section("6.5.1"));
0483: status = false;
0484: }
0485:
0486: /*
0487: * Only a stateful container-managed transaction demarcation
0488: * session bean MAY implement the SessionSynchronization interface.
0489: *
0490: * A stateless Session bean MUST NOT implement the
0491: * SessionSynchronization interface.
0492: *
0493: * Spec 6.5.3
0494: */
0495: if (hasSessionSynchronizationInterface(bean)) {
0496: if (session.isStateless()) {
0497: fireSpecViolationEvent(session, new Section(
0498: "6.5.3.a"));
0499: status = false;
0500: }
0501:
0502: if (session.isBeanManagedTx()) {
0503: fireSpecViolationEvent(session, new Section(
0504: "6.5.3.b"));
0505: status = false;
0506: }
0507: }
0508:
0509: /*
0510: * A session bean MUST implement AT LEAST one ejbCreate method.
0511: *
0512: * Spec 6.5.5
0513: */
0514: if (!hasEJBCreateMethod(bean, true)) {
0515: fireSpecViolationEvent(session, new Section("6.5.5"));
0516: status = false;
0517: }
0518:
0519: /*
0520: * A session with bean-managed transaction demarcation CANNOT
0521: * implement the SessionSynchronization interface.
0522: *
0523: * Spec 6.6.1 (table 2)
0524: */
0525: if (hasSessionSynchronizationInterface(bean)
0526: && session.isBeanManagedTx()) {
0527: fireSpecViolationEvent(session, new Section("6.6.1"));
0528: status = false;
0529: }
0530:
0531: /*
0532: * The session bean class MUST be defined as public.
0533: *
0534: * Spec 6.10.2
0535: */
0536: if (!isPublic(bean)) {
0537: fireSpecViolationEvent(session, new Section("6.10.2.a"));
0538: status = false;
0539: }
0540:
0541: /*
0542: * The session bean class MUST NOT be final.
0543: *
0544: * Spec 6.10.2
0545: */
0546: if (isFinal(bean)) {
0547: fireSpecViolationEvent(session, new Section("6.10.2.b"));
0548: status = false;
0549: }
0550:
0551: /*
0552: * The session bean class MUST NOT be abstract.
0553: *
0554: * Spec 6.10.2
0555: */
0556: if (isAbstract(bean)) {
0557: fireSpecViolationEvent(session, new Section("6.10.2.c"));
0558: status = false;
0559: }
0560:
0561: /*
0562: * The session bean class MUST have a public constructor that
0563: * takes no arguments.
0564: *
0565: * Spec 6.10.2
0566: */
0567: if (!hasDefaultConstructor(bean)) {
0568: fireSpecViolationEvent(session, new Section("6.10.2.d"));
0569: status = false;
0570: }
0571:
0572: /*
0573: * The session bean class MUST NOT define the finalize() method.
0574: *
0575: * Spec 6.10.2
0576: */
0577: if (hasFinalizer(bean)) {
0578: fireSpecViolationEvent(session, new Section("6.10.2.e"));
0579: status = false;
0580: }
0581:
0582: /*
0583: * The ejbCreate(...) method signatures MUST follow these rules:
0584: *
0585: * - The method MUST be declared as public
0586: * - The method MUST NOT be declared as final or static
0587: * - The return type MUST be void
0588: * - The method arguments MUST be legal types for RMI/IIOP
0589: *
0590: * Spec 6.10.3
0591: */
0592: if (hasEJBCreateMethod(bean, true)) {
0593: Iterator it = getEJBCreateMethods(bean);
0594: while (it.hasNext()) {
0595: Method ejbCreate = (Method) it.next();
0596:
0597: if (!isPublic(ejbCreate)) {
0598: fireSpecViolationEvent(session, ejbCreate,
0599: new Section("6.10.3.a"));
0600: status = false;
0601: }
0602:
0603: if ((isFinal(ejbCreate)) || (isStatic(ejbCreate))) {
0604: fireSpecViolationEvent(session, ejbCreate,
0605: new Section("6.10.3.b"));
0606: status = false;
0607: }
0608:
0609: if (!hasVoidReturnType(ejbCreate)) {
0610: fireSpecViolationEvent(session, ejbCreate,
0611: new Section("6.10.3.c"));
0612: status = false;
0613: }
0614:
0615: if (!hasLegalRMIIIOPArguments(ejbCreate)) {
0616: fireSpecViolationEvent(session, ejbCreate,
0617: new Section("6.10.3.d"));
0618: status = false;
0619: }
0620: } // while
0621: }
0622: } catch (ClassNotFoundException e) {
0623: /*
0624: * The Bean Provider MUST specify the fully-qualified name of the
0625: * Java class that implements the enterprise bean's business
0626: * methods.
0627: *
0628: * Spec 16.2
0629: */
0630: fireSpecViolationEvent(session, new Section("16.2.b"));
0631: status = false;
0632: }
0633:
0634: return status;
0635: }
0636:
0637: /*
0638: *************************************************************************
0639: *
0640: * VERIFY ENTITY BEAN HOME INTERFACE
0641: *
0642: *************************************************************************
0643: */
0644:
0645: private boolean verifyEntityHome(EntityMetaData entity) {
0646: boolean status = true;
0647:
0648: String name = entity.getHome();
0649: if (name == null)
0650: return false;
0651:
0652: try {
0653: Class home = classloader.loadClass(name);
0654:
0655: /*
0656: * Entity bean's home interface MUST extend the javax.ejb.EJBHome
0657: * interface.
0658: *
0659: * Spec 9.2.8
0660: */
0661: if (!hasEJBHomeInterface(home)) {
0662: fireSpecViolationEvent(entity, new Section("9.2.8.a"));
0663: status = false;
0664: }
0665:
0666: /*
0667: * The methods defined in the entity bean's home interface MUST
0668: * have valid RMI-IIOP argument types.
0669: *
0670: * The methods defined in the entity bean's home interface MUST
0671: * have valid RMI-IIOP return types.
0672: *
0673: * The methods defined in the entity bean's home interface MUST
0674: * have java.rmi.RemoteException in their throws clause.
0675: *
0676: * Spec 9.2.8
0677: */
0678: Iterator homeMethods = Arrays.asList(home.getMethods())
0679: .iterator();
0680: while (homeMethods.hasNext()) {
0681: Method method = (Method) homeMethods.next();
0682:
0683: if (!hasLegalRMIIIOPArguments(method)) {
0684: fireSpecViolationEvent(entity, method, new Section(
0685: "9.2.8.b"));
0686:
0687: status = false;
0688: }
0689:
0690: if (!hasLegalRMIIIOPReturnType(method)) {
0691: fireSpecViolationEvent(entity, method, new Section(
0692: "9.2.8.c"));
0693: status = false;
0694: }
0695:
0696: if (!throwsRemoteException(method)) {
0697: fireSpecViolationEvent(entity, method, new Section(
0698: "9.2.8.d"));
0699: status = false;
0700: }
0701: } // while
0702:
0703: /*
0704: * Each method defined in the entity bean's home interface must be
0705: * one of the following:
0706: *
0707: * - a create method
0708: * - a finder method
0709: *
0710: * Spec 9.2.8
0711: */
0712: homeMethods = Arrays.asList(home.getMethods()).iterator();
0713: while (homeMethods.hasNext()) {
0714: Method method = (Method) homeMethods.next();
0715:
0716: // Do not check the methods of the javax.ejb.EJBHome interface
0717: if (method.getDeclaringClass().getName().equals(
0718: EJB_HOME_INTERFACE))
0719: continue;
0720:
0721: if (!(isCreateMethod(method) || isFinderMethod(method))) {
0722: fireSpecViolationEvent(entity, method, new Section(
0723: "9.2.8.e"));
0724: status = false;
0725: }
0726: }
0727:
0728: /*
0729: * Each create(...) method in the entity bean's home interface MUST
0730: * have a matching ejbCreate(...) method in the entity bean's class.
0731: *
0732: * Each create(...) method in the entity bean's home interface MUST
0733: * have the same number and types of arguments to its matching
0734: * ejbCreate(...) method.
0735: *
0736: * The return type for a create(...) method MUST be the entity
0737: * bean's remote interface type.
0738: *
0739: * All the exceptions defined in the throws clause of the matching
0740: * ejbCreate(...) and ejbPostCreate(...) methods of the enterprise
0741: * bean class MUST be included in the throws clause of a matching
0742: * create(...) method.
0743: *
0744: * The throws clause of a create(...) method MUST include the
0745: * javax.ejb.CreateException.
0746: *
0747: * Spec 9.2.8
0748: */
0749:
0750: try {
0751: String beanClass = entity.getEjbClass();
0752: Class bean = classloader.loadClass(beanClass);
0753:
0754: Iterator createMethods = getCreateMethods(home);
0755: while (createMethods.hasNext()) {
0756: Method create = (Method) createMethods.next();
0757:
0758: if (!hasMatchingEJBCreate(bean, create)) {
0759: fireSpecViolationEvent(entity, create,
0760: new Section("9.2.8.f"));
0761: status = false;
0762: }
0763:
0764: if (!hasRemoteReturnType(entity, create)) {
0765: fireSpecViolationEvent(entity, create,
0766: new Section("9.2.8.g"));
0767: status = false;
0768: }
0769:
0770: if (hasMatchingEJBCreate(bean, create)
0771: && hasMatchingEJBPostCreate(bean, create)) {
0772: Method ejbCreate = getMatchingEJBCreate(bean,
0773: create);
0774: Method ejbPostCreate = getMatchingEJBPostCreate(
0775: bean, create);
0776:
0777: if (!(hasMatchingExceptions(ejbCreate, create) && hasMatchingExceptions(
0778: ejbPostCreate, create))) {
0779: fireSpecViolationEvent(entity, create,
0780: new Section("9.2.8.h"));
0781: status = false;
0782: }
0783: }
0784:
0785: if (!throwsCreateException(create)) {
0786: fireSpecViolationEvent(entity, create,
0787: new Section("9.2.8.i"));
0788: status = false;
0789: }
0790: }
0791: } catch (ClassNotFoundException ignored) {
0792: }
0793:
0794: /*
0795: * Each finder method MUST match one of the ejbFind<METHOD> methods
0796: * defined in the entity bean class.
0797: *
0798: * The matching ejbFind<METHOD> method MUST have the same number and
0799: * types of arguments.
0800: *
0801: * The return type for a find<METHOD> method MUST be the entity
0802: * bean's remote interface type (single-object finder) or a
0803: * collection thereof (for a multi-object finder).
0804: *
0805: * All the exceptions defined in the throws clause of an ejbFind
0806: * method of the entity bean class MUST be included in the throws
0807: * clause of the matching find method of the home interface.
0808: *
0809: * The throws clause of a finder method MUST include the
0810: * javax.ejb.FinderException.
0811: *
0812: * Spec 9.2.8
0813: */
0814: try {
0815: String beanClass = entity.getEjbClass();
0816: Class bean = classloader.loadClass(beanClass);
0817:
0818: Iterator finderMethods = getFinderMethods(home);
0819: while (finderMethods.hasNext()) {
0820: Method finder = (Method) finderMethods.next();
0821:
0822: if ((entity.isBMP())
0823: && (!hasMatchingEJBFind(bean, finder))) {
0824: fireSpecViolationEvent(entity, finder,
0825: new Section("9.2.8.j"));
0826: status = false;
0827: }
0828:
0829: if (!(hasRemoteReturnType(entity, finder) || isMultiObjectFinder(finder))) {
0830: fireSpecViolationEvent(entity, finder,
0831: new Section("9.2.8.k"));
0832: status = false;
0833: }
0834:
0835: if ((entity.isBMP())
0836: && (hasMatchingEJBFind(bean, finder))) {
0837: Method ejbFind = getMatchingEJBFind(bean,
0838: finder);
0839: if (!(hasMatchingExceptions(ejbFind, finder))) {
0840: fireSpecViolationEvent(entity, finder,
0841: new Section("9.2.8.l"));
0842: status = false;
0843: }
0844: }
0845:
0846: if (!throwsFinderException(finder)) {
0847: fireSpecViolationEvent(entity, finder,
0848: new Section("9.2.8.m"));
0849: status = false;
0850: }
0851: }
0852: } catch (ClassNotFoundException ignored) {
0853: }
0854: } catch (ClassNotFoundException e) {
0855: /*
0856: * The bean provider MUST specify the fully-qualified name of the
0857: * enterprise bean's home interface in the <home> element.
0858: *
0859: * Spec 16.2
0860: */
0861: fireSpecViolationEvent(entity, new Section("16.2.c"));
0862: status = false;
0863: }
0864:
0865: return status;
0866: }
0867:
0868: /*
0869: *************************************************************************
0870: *
0871: * VERIFY ENTITY BEAN REMOTE INTERFACE
0872: *
0873: *************************************************************************
0874: */
0875:
0876: private boolean verifyEntityRemote(EntityMetaData entity) {
0877: boolean status = true;
0878:
0879: String name = entity.getRemote();
0880: if (name == null)
0881: return false;
0882:
0883: try {
0884: Class remote = classloader.loadClass(name);
0885:
0886: /*
0887: * Entity bean's remote interface MUST extend
0888: * the javax.ejb.EJBObject interface.
0889: *
0890: * Spec 9.2.7
0891: */
0892: if (!hasEJBObjectInterface(remote)) {
0893: fireSpecViolationEvent(entity, new Section("9.2.7.a"));
0894: status = false;
0895: }
0896:
0897: /*
0898: * The methods defined in the entity bean's remote interface MUST
0899: * have valid RMI-IIOP argument types.
0900: *
0901: * The methods defined in the entity bean's home interface MUST
0902: * have valid RMI-IIOP return types.
0903: *
0904: * The methods defined in the entity bean's home interface MUST
0905: * have java.rmi.RemoteException in their throws clause.
0906: *
0907: * Spec 9.2.7
0908: */
0909: Iterator remoteMethods = Arrays.asList(remote.getMethods())
0910: .iterator();
0911: while (remoteMethods.hasNext()) {
0912: Method method = (Method) remoteMethods.next();
0913:
0914: if (!hasLegalRMIIIOPArguments(method)) {
0915: fireSpecViolationEvent(entity, method, new Section(
0916: "9.2.7.b"));
0917: status = false;
0918: }
0919:
0920: if (!hasLegalRMIIIOPReturnType(method)) {
0921: fireSpecViolationEvent(entity, method, new Section(
0922: "9.2.7.c"));
0923: status = false;
0924: }
0925:
0926: if (!hasLegalRMIIIOPExceptionTypes(method)) {
0927: fireSpecViolationEvent(entity, method, new Section(
0928: "9.2.7.h"));
0929: status = false;
0930: }
0931:
0932: if (!throwsRemoteException(method)) {
0933: fireSpecViolationEvent(entity, method, new Section(
0934: "9.2.7.d"));
0935: status = false;
0936: }
0937: } // while
0938:
0939: /*
0940: * For each method defined in the remote interface, there MUST be
0941: * a matching method in the entity bean's class. The matching
0942: * method MUST have:
0943: *
0944: * - The same name.
0945: * - The same number and types of its arguments.
0946: * - The same return type.
0947: * - All the exceptions defined in the throws clause of the
0948: * matching method of the enterprise Bean class must be
0949: * defined in the throws clause of the method of the remote
0950: * interface.
0951: *
0952: * Spec 9.2.7
0953: */
0954:
0955: try {
0956: String beanClass = entity.getEjbClass();
0957: Class bean = classloader.loadClass(beanClass);
0958:
0959: remoteMethods = Arrays.asList(remote.getMethods())
0960: .iterator();
0961: while (remoteMethods.hasNext()) {
0962: Method method = (Method) remoteMethods.next();
0963:
0964: // Do not check the methods of the javax.ejb.EJBObject interface
0965: if (method.getDeclaringClass().getName().equals(
0966: EJB_OBJECT_INTERFACE))
0967: continue;
0968:
0969: if (!hasMatchingMethod(bean, method)) {
0970: fireSpecViolationEvent(entity, method,
0971: new Section("9.2.7.e"));
0972: status = false;
0973: }
0974:
0975: if (hasMatchingMethod(bean, method)) {
0976: try {
0977: Method beanMethod = bean.getMethod(method
0978: .getName(), method
0979: .getParameterTypes());
0980:
0981: if (!hasMatchingReturnType(beanMethod,
0982: method)) {
0983: fireSpecViolationEvent(entity, method,
0984: new Section("9.2.7.f"));
0985: status = false;
0986: }
0987:
0988: if (!hasMatchingExceptions(beanMethod,
0989: method)) {
0990: fireSpecViolationEvent(entity, method,
0991: new Section("9.2.7.g"));
0992: status = false;
0993: }
0994: } catch (NoSuchMethodException ignored) {
0995: }
0996: }
0997: }
0998: } catch (ClassNotFoundException ignored) {
0999: }
1000: } catch (ClassNotFoundException e) {
1001: /*
1002: * The Bean Provider MUST specify the fully-qualified name of the
1003: * enterprise bean's remote interface in the <remote> element.
1004: *
1005: * Spec 16.2
1006: */
1007: fireSpecViolationEvent(entity, new Section("16.2.d"));
1008: status = false;
1009: }
1010:
1011: return status;
1012: }
1013:
1014: /*
1015: *************************************************************************
1016: *
1017: * VERIFY ENTITY BEAN CLASS
1018: *
1019: *************************************************************************
1020: */
1021:
1022: private boolean verifyEntityBean(EntityMetaData entity) {
1023: boolean status = true;
1024:
1025: String name = entity.getEjbClass();
1026:
1027: try {
1028: Class bean = classloader.loadClass(name);
1029:
1030: /*
1031: * The enterprise bean class MUST implement, directly or
1032: * indirectly, the javax.ejb.EntityBean interface.
1033: *
1034: * Spec 9.2.2
1035: */
1036: if (!hasEntityBeanInterface(bean)) {
1037: fireSpecViolationEvent(entity, new Section("9.2.2.a"));
1038: status = false;
1039: }
1040:
1041: /*
1042: * The entity bean class MUST be defined as public.
1043: *
1044: * Spec 9.2.2
1045: */
1046: if (!isPublic(bean)) {
1047: fireSpecViolationEvent(entity, new Section("9.2.2.b"));
1048: status = false;
1049: }
1050:
1051: /*
1052: * The entity bean class MUST NOT be defined as abstract.
1053: *
1054: * Spec 9.2.2
1055: */
1056: if (isAbstract(bean)) {
1057: fireSpecViolationEvent(entity, new Section("9.2.2.c"));
1058: status = false;
1059: }
1060:
1061: /*
1062: * The entity bean class MUST NOT be defined as final.
1063: *
1064: * Spec 9.2.2
1065: */
1066: if (isFinal(bean)) {
1067: fireSpecViolationEvent(entity, new Section("9.2.2.d"));
1068: status = false;
1069: }
1070:
1071: /*
1072: * The entity bean class MUST define a public constructor that
1073: * takes no arguments
1074: *
1075: * Spec 9.2.2
1076: */
1077: if (!hasDefaultConstructor(bean)) {
1078: fireSpecViolationEvent(entity, new Section("9.2.2.e"));
1079: status = false;
1080: }
1081:
1082: /*
1083: * The entity bean class MUST NOT define the finalize() method.
1084: *
1085: * Spec 9.2.2
1086: */
1087: if (hasFinalizer(bean)) {
1088: fireSpecViolationEvent(entity, new Section("9.2.2.f"));
1089: status = false;
1090: }
1091:
1092: /*
1093: * The ejbCreate(...) method signatures MUST follow these rules:
1094: *
1095: * - The method MUST be declared as public
1096: * - The method MUST NOT be declared as final or static
1097: * - The return type MUST be the entity bean's primary key type
1098: * - The method arguments MUST be legal types for RMI/IIOP
1099: * - The method return value type MUST be legal type for RMI/IIOP
1100: *
1101: * Spec 9.2.3
1102: */
1103: if (hasEJBCreateMethod(bean, false)) {
1104: Iterator it = getEJBCreateMethods(bean);
1105: while (it.hasNext()) {
1106: Method ejbCreate = (Method) it.next();
1107:
1108: if (!isPublic(ejbCreate)) {
1109: fireSpecViolationEvent(entity, ejbCreate,
1110: new Section("9.2.3.a"));
1111: status = false;
1112: }
1113:
1114: if ((isFinal(ejbCreate)) || (isStatic(ejbCreate))) {
1115: fireSpecViolationEvent(entity, ejbCreate,
1116: new Section("9.2.3.b"));
1117: status = false;
1118: }
1119:
1120: if (!hasPrimaryKeyReturnType(entity, ejbCreate)) {
1121: fireSpecViolationEvent(entity, ejbCreate,
1122: new Section("9.2.3.c"));
1123: status = false;
1124: }
1125:
1126: if (!hasLegalRMIIIOPArguments(ejbCreate)) {
1127: fireSpecViolationEvent(entity, ejbCreate,
1128: new Section("9.2.3.d"));
1129: status = false;
1130: }
1131:
1132: if (!hasLegalRMIIIOPReturnType(ejbCreate)) {
1133: fireSpecViolationEvent(entity, ejbCreate,
1134: new Section("9.2.3.e"));
1135: status = false;
1136: }
1137: }
1138: }
1139:
1140: /*
1141: * For each ejbCreate(...) method, the entity bean class MUST
1142: * define a matching ejbPostCreate(...) method.
1143: *
1144: * The ejbPostCreate(...) method MUST follow these rules:
1145: *
1146: * - the method MUST be declared as public
1147: * - the method MUST NOT be declared as final or static
1148: * - the return type MUST be void
1149: * - the method arguments MUST be the same as the matching
1150: * ejbCreate(...) method
1151: *
1152: * Spec 9.2.4
1153: */
1154: if (hasEJBCreateMethod(bean, false)) {
1155: Iterator it = getEJBCreateMethods(bean);
1156: while (it.hasNext()) {
1157: Method ejbCreate = (Method) it.next();
1158:
1159: if (!hasMatchingEJBPostCreate(bean, ejbCreate)) {
1160: fireSpecViolationEvent(entity, ejbCreate,
1161: new Section("9.2.4.a"));
1162: status = false;
1163: }
1164:
1165: if (hasMatchingEJBPostCreate(bean, ejbCreate)) {
1166: Method ejbPostCreate = getMatchingEJBPostCreate(
1167: bean, ejbCreate);
1168:
1169: if (!isPublic(ejbPostCreate)) {
1170: fireSpecViolationEvent(entity,
1171: ejbPostCreate, new Section(
1172: "9.2.4.b"));
1173: status = false;
1174: }
1175:
1176: if (isStatic(ejbPostCreate)) {
1177: fireSpecViolationEvent(entity,
1178: ejbPostCreate, new Section(
1179: "9.2.4.c"));
1180: status = false;
1181: }
1182:
1183: if (isFinal(ejbPostCreate)) {
1184: fireSpecViolationEvent(entity,
1185: ejbPostCreate, new Section(
1186: "9.2.4.d"));
1187: status = false;
1188: }
1189:
1190: if (!hasVoidReturnType(ejbPostCreate)) {
1191: fireSpecViolationEvent(entity,
1192: ejbPostCreate, new Section(
1193: "9.2.4.e"));
1194: status = false;
1195: }
1196: }
1197: }
1198: }
1199:
1200: /*
1201: * Every entity bean MUST define the ejbFindByPrimaryKey method.
1202: *
1203: * The return type for the ejbFindByPrimaryKey method MUST be the
1204: * primary key type.
1205: *
1206: * The ejbFindByPrimaryKey method MUST be a single-object finder.
1207: *
1208: * Spec 9.2.5
1209: */
1210: if (entity.isBMP() && (!hasEJBFindByPrimaryKey(bean))) {
1211: fireSpecViolationEvent(entity, new Section("9.2.5.a"));
1212: status = false;
1213: }
1214:
1215: if (hasEJBFindByPrimaryKey(bean)) {
1216: Method ejbFindByPrimaryKey = getEJBFindByPrimaryKey(bean);
1217:
1218: if (!hasPrimaryKeyReturnType(entity,
1219: ejbFindByPrimaryKey)) {
1220: fireSpecViolationEvent(entity, ejbFindByPrimaryKey,
1221: new Section("9.2.5.b"));
1222: status = false;
1223: }
1224:
1225: if (!isSingleObjectFinder(entity, ejbFindByPrimaryKey)) {
1226: fireSpecViolationEvent(entity, ejbFindByPrimaryKey,
1227: new Section("9.2.5.c"));
1228: status = false;
1229: }
1230: }
1231:
1232: /*
1233: * A finder method MUST be declared as public.
1234: *
1235: * A finder method MUST NOT be declared as static.
1236: *
1237: * A finder method MUST NOT be declared as final.
1238: *
1239: * The finder method argument types MUST be legal types
1240: * for RMI/IIOP
1241: *
1242: * The finder method return type MUST be either the entity bean's
1243: * primary key type, or java.lang.util.Enumeration interface or
1244: * java.lang.util.Collection interface.
1245: *
1246: * Spec 9.2.5
1247: */
1248: if (hasFinderMethod(bean)) {
1249: Iterator it = getEJBFindMethods(bean);
1250: while (it.hasNext()) {
1251: Method finder = (Method) it.next();
1252:
1253: if (!isPublic(finder)) {
1254: fireSpecViolationEvent(entity, finder,
1255: new Section("9.2.5.d"));
1256: status = false;
1257: }
1258:
1259: if (isFinal(finder)) {
1260: fireSpecViolationEvent(entity, finder,
1261: new Section("9.2.5.e"));
1262: status = false;
1263: }
1264:
1265: if (isStatic(finder)) {
1266: fireSpecViolationEvent(entity, finder,
1267: new Section("9.2.5.f"));
1268: status = false;
1269: }
1270:
1271: if (!hasLegalRMIIIOPArguments(finder)) {
1272: fireSpecViolationEvent(entity, finder,
1273: new Section("9.2.5.g"));
1274: status = false;
1275: }
1276:
1277: if (!(isSingleObjectFinder(entity, finder) || isMultiObjectFinder(finder))) {
1278: fireSpecViolationEvent(entity, finder,
1279: new Section("9.2.5.h"));
1280: status = false;
1281: }
1282: }
1283: }
1284: } catch (ClassNotFoundException e) {
1285: /*
1286: * The Bean Provider MUST specify the fully-qualified name of the
1287: * Java class that implements the enterprise bean's business
1288: * methods.
1289: *
1290: * Spec 16.2
1291: */
1292: fireSpecViolationEvent(entity, new Section("16.2.b"));
1293: status = false;
1294: }
1295:
1296: return status;
1297: }
1298:
1299: private boolean verifyPrimaryKey(EntityMetaData entity) {
1300: boolean status = true;
1301:
1302: if (entity.getPrimaryKeyClass() == null
1303: || entity.getPrimaryKeyClass().length() == 0) {
1304: fireSpecViolationEvent(entity, new Section("16.5.a"));
1305: return false; // We can't get any further if there's no PK class specified!
1306: }
1307:
1308: if (entity.getPrimKeyField() == null
1309: || entity.getPrimKeyField().length() == 0) {
1310: Class cls = null;
1311:
1312: try {
1313: cls = classloader
1314: .loadClass(entity.getPrimaryKeyClass());
1315:
1316: if (entity.isCMP()) {
1317: if (!isPublic(cls)) {
1318: fireSpecViolationEvent(entity, new Section(
1319: "9.4.7.2.a"));
1320: status = false;
1321: }
1322:
1323: if (!isAllFieldsPublic(cls)) {
1324: fireSpecViolationEvent(entity, new Section(
1325: "9.4.7.2.b"));
1326: status = false;
1327: }
1328:
1329: if (!hasANonStaticField(cls)) {
1330: fireSpecViolationEvent(entity, new Section(
1331: "9.4.7.2.c"));
1332: status = false;
1333: }
1334: }
1335:
1336: if (!cls.getName().equals("java.lang.Object")) {
1337: Object one, two;
1338: try {
1339: one = cls.newInstance();
1340: two = cls.newInstance();
1341: try {
1342: if (!one.equals(two)) {
1343: fireSpecViolationEvent(entity,
1344: new Section("9.2.9.b"));
1345: status = false;
1346: }
1347: } catch (NullPointerException e) {
1348: } // That's OK - the implementor expected the fields to have values
1349: try {
1350: if (one.hashCode() != two.hashCode()) {
1351: fireSpecViolationEvent(entity,
1352: new Section("9.2.9.c"));
1353: status = false;
1354: }
1355: } catch (NullPointerException e) {
1356: } // That's OK - the implementor expected the fields to have values
1357: } catch (IllegalAccessException e) {
1358: // [FIXME] The two error messages below are incorrect.
1359: // The RMI-IDL language mapping does not require
1360: // the value types to have a no args constructor.
1361: // [JPL]
1362: //
1363: //fireSpecViolationEvent(entity, new Section("9.2.9.a"));
1364: //status = false;
1365: } catch (InstantiationException e) {
1366: //fireSpecViolationEvent(entity, new Section("9.2.9.a"));
1367: //status = false;
1368: }
1369: }
1370: } catch (ClassNotFoundException e) {
1371: fireSpecViolationEvent(entity, new Section("16.2.e"));
1372: status = false; // Can't do any other checks if the class is null!
1373: }
1374: } else {
1375: if (entity.isBMP()) {
1376: fireSpecViolationEvent(entity, new Section("9.4.7.1.a"));
1377: status = false;
1378: }
1379:
1380: try {
1381: Class fieldClass = classloader.loadClass(entity
1382: .getEjbClass());
1383: Field field = null;
1384: try {
1385: field = fieldClass.getField(entity
1386: .getPrimKeyField());
1387: if (!entity.getPrimaryKeyClass().equals(
1388: field.getType().getName())) {
1389: fireSpecViolationEvent(entity, new Section(
1390: "9.4.7.1.c"));
1391: status = false;
1392: }
1393:
1394: Iterator it = entity.getCMPFields();
1395: boolean found = false;
1396: while (it.hasNext()) {
1397: String fieldName = (String) it.next();
1398: if (fieldName.equals(entity.getPrimKeyField())) {
1399: found = true;
1400: break;
1401: }
1402: }
1403:
1404: if (!found) {
1405: fireSpecViolationEvent(entity, new Section(
1406: "9.4.7.1.d"));
1407: status = false;
1408: }
1409: } catch (NoSuchFieldException e) {
1410: fireSpecViolationEvent(entity, new Section(
1411: "9.4.7.1.b"));
1412: status = false;
1413: }
1414: } catch (ClassNotFoundException e) {
1415: } // reported elsewhere
1416: }
1417:
1418: return status;
1419: }
1420:
1421: }
1422:
1423: /*
1424: vim:ts=3:sw=3:et
1425: */
|