blob: c09dbaa9fa5a677699896e8a59f44980ce1fbda3 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2001, 2005 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jst.j2ee.model.internal.validation;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.eclipse.jem.java.Field;
import org.eclipse.jem.java.JavaClass;
import org.eclipse.jem.java.JavaHelpers;
import org.eclipse.jem.java.Method;
import org.eclipse.jst.j2ee.ejb.EnterpriseBean;
import org.eclipse.wst.validation.internal.core.ValidationException;
import org.eclipse.wst.validation.internal.provisional.core.IMessage;
/**
* @version 1.0
* @author
*/
public abstract class ABeanClassVRule extends ATypeVRule implements IEJBType {
protected final static long[] BASE_TYPES = new long[]{ITypeConstants.JAVA_LANG_OBJECT};
protected final static int MESSAGE_REMOTE_EXCEPTION_SEVERITY = IEJBValidationContext.WARNING; // Deprecated use of RemoteException.
public long[] getBaseTypes() {
return BASE_TYPES;
}
public Object getTarget(Object parent, Object clazz) {
if(parent == null) {
return null;
}
return ((EnterpriseBean)parent).getEjbClass();
}
public long getDefaultMethodType() {
return HELPER;
}
public void validate(IEJBValidationContext vc, EnterpriseBean bean, JavaClass clazz) throws ValidationCancelledException, InvalidInputException, ValidationException {
if(!followAbstractRules(clazz)) {
IMessage message = MessageUtility.getUtility().getMessage(vc, IEJBValidatorMessageConstants.CHKJ2014, IEJBValidationContext.WARNING, bean, clazz, this);
vc.addMessage(message);
}
if(!followPublicRules(clazz)) {
IMessage message = MessageUtility.getUtility().getMessage(vc, IEJBValidatorMessageConstants.CHKJ2022, IEJBValidationContext.WARNING, bean, clazz, this);
vc.addMessage(message);
}
if(!followFinalRules(clazz)) {
IMessage message = MessageUtility.getUtility().getMessage(vc, IEJBValidatorMessageConstants.CHKJ2015, IEJBValidationContext.WARNING, bean, clazz, this);
vc.addMessage(message);
}
validateAppendixB(vc, bean, clazz);
}
public final static List getRemoteHomeMethodsExtended(List[] methodsExtendedList) {
return methodsExtendedList[0];
}
public final static List getLocalHomeMethodsExtended(List[] methodsExtendedList) {
return methodsExtendedList[1];
}
public final static List getRemoteComponentMethodsExtended(List[] methodsExtendedList) {
return methodsExtendedList[2];
}
public final static List getLocalComponentMethodsExtended(List[] methodsExtendedList) {
return methodsExtendedList[3];
}
public final static List getBeanClassMethodsExtended(List[] methodsExtendedList) {
return methodsExtendedList[4];
}
public final List[] getMethodsExtended(IEJBValidationContext vc, EnterpriseBean bean, JavaClass clazz) {
// A bean class needs the following classes' extended methods:
// 1. remote home
// 2. local home
// 3. remote component
// 4. local component
// 5. bean class (when searching for a matching ejbPostCreate method).
// If a particular bean doesn't use a remote view or local view,
// then the corresponding entry in the array will be null.
List[] result = new List[5];
JavaClass remoteHome = bean.getHomeInterface();
if(remoteHome != null) {
result[0] = remoteHome.getMethodsExtended();
}
else {
result[0] = null;
}
JavaClass localHome = bean.getLocalHomeInterface();
if(localHome != null) {
result[1] = localHome.getMethodsExtended();
}
else {
result[1] = null;
}
JavaClass remoteComponent = bean.getRemoteInterface();
if(remoteComponent != null) {
result[2] = remoteComponent.getMethodsExtended();
}
else {
result[2] = null;
}
JavaClass localComponent = bean.getLocalInterface();
if(localComponent != null) {
result[3] = localComponent.getMethodsExtended();
}
else {
result[3] = null;
}
JavaClass beanClass = bean.getEjbClass();
if(beanClass != null) {
result[4] = beanClass.getMethodsExtended();
}
else {
result[4] = null;
}
return result;
}
public final List[] getFieldsExtended(IEJBValidationContext vc, EnterpriseBean bean, JavaClass clazz) {
// Never check that a bean class' field is defined on another class
// of the bean.
return null;
}
protected abstract boolean shouldBeFinal(JavaClass clazz);
protected abstract boolean shouldBePublic(JavaClass clazz);
protected abstract boolean shouldBeAbstract(JavaClass clazz);
protected abstract boolean shouldValidateTransientField();
protected abstract JavaHelpers getEjbCreateReturnType(EnterpriseBean bean, Method method) throws InvalidInputException;
protected abstract String getEjbCreateReturnTypeName(EnterpriseBean bean, Method method) throws InvalidInputException;
public abstract String getMatchingHomeMethodName(IEJBValidationContext vc, EnterpriseBean bean, JavaClass clazz, Method method, List[] methodsExtendedList);
public String getMatchingEjbHomeMethodName(IEJBValidationContext vc, Method method) {
// Section number stating this name convention?
String methodName = method.getName();
// Strip the "ejbHome" off, strip off the next character, and replace that character with a lowercase version of that character
StringBuffer buffer = new StringBuffer(Character.toLowerCase(methodName.charAt(0)));
buffer.append(method.getName().substring(8));
return buffer.toString();
}
public String getMatchingEjbCreateMethodName(IEJBValidationContext vc, Method method) {
StringBuffer buffer = new StringBuffer(IMethodAndFieldConstants.PREFIX_C);
// Strip the "ejbC" off of "create" and replace with "c"
buffer.append(method.getName().substring(4));
return buffer.toString();
}
public String getMatchingEjbPostCreateMethodName(IEJBValidationContext vc, Method method) {
StringBuffer buffer = new StringBuffer(IMethodAndFieldConstants.PREFIX_C);
// Strip the "ejbPostC" off of "create" and replace with "c"
buffer.append(method.getName().substring(8));
return buffer.toString();
}
public String getMatchingEjbFindMethodName(IEJBValidationContext vc, Method method) {
StringBuffer buffer = new StringBuffer(IMethodAndFieldConstants.PREFIX_F);
// Strip the "ejbF" off of "ejbFind" and replace with "f"
buffer.append(method.getName().substring(4));
return buffer.toString();
}
public String getMatchingBusinessMethodName(IEJBValidationContext vc, Method method) {
return method.getName();
}
/*
* The given method is not supposed to have a matching method.
*/
public String getNoMatchingMethodName(IEJBValidationContext vc, Method method) {
return null; // not supposed to have a matching method
}
public final boolean followFinalRules(JavaClass clazz) {
if(shouldBeFinal(clazz)) {
return clazz.isFinal();
}
return !clazz.isFinal();
}
public final boolean followPublicRules(JavaClass clazz) {
if(shouldBePublic(clazz)) {
return clazz.isPublic();
}
return !clazz.isPublic();
}
public final boolean followAbstractRules(JavaClass clazz) {
if(shouldBeAbstract(clazz)) {
return clazz.isAbstract();
}
return !clazz.isAbstract();
}
public void validateEjbCreateMethod(IEJBValidationContext vc, EnterpriseBean bean, JavaClass clazz, Method method, List[] methodsExtendedLists) throws ValidationCancelledException, InvalidInputException, ValidationException {
if(!ValidationRuleUtility.isPublic(method)) {
IMessage message = MessageUtility.getUtility().getMessage(vc, IMessagePrefixEjb20Constants.CHKJ2421, IEJBValidationContext.WARNING, bean, clazz, method, this);
vc.addMessage(message);
}
if(method.isFinal()) {
IMessage message = MessageUtility.getUtility().getMessage(vc, IMessagePrefixEjb20Constants.CHKJ2422, IEJBValidationContext.WARNING, bean, clazz, method, this);
vc.addMessage(message);
}
if(method.isStatic()) {
IMessage message = MessageUtility.getUtility().getMessage(vc, IMessagePrefixEjb20Constants.CHKJ2423, IEJBValidationContext.WARNING, bean, clazz, method, this);
vc.addMessage(message);
}
JavaHelpers retType = getEjbCreateReturnType(bean, method);
if((retType == null) || (!ValidationRuleUtility.isAssignableFrom(method.getReturnType(), retType))) {
String retTypeName = (retType == null) ? getEjbCreateReturnTypeName(bean, method) : retType.getJavaName();
IMessage message = MessageUtility.getUtility().getMessage(vc, IMessagePrefixEjb20Constants.CHKJ2424, IEJBValidationContext.WARNING, bean, clazz, method, new String[]{retTypeName}, this);
vc.addMessage(message);
}
validateRMI_IIOPTypeRules(vc, bean, clazz, method, methodsExtendedLists, true);
if(validateEjbCreateMethodExceptions()) {
if(!followRemoteExceptionRules(bean, method)) {
IMessage message = MessageUtility.getUtility().getMessage(vc, IMessagePrefixEjb20Constants.CHKJ2503_ejbCreate, IEJBValidationContext.WARNING, bean, clazz, method, this);
vc.addMessage(message);
}
}
}
public boolean validateEjbCreateMethodExceptions() {
return true;
}
public void validateEjbPostCreateMethod(IEJBValidationContext vc, EnterpriseBean bean, JavaClass clazz, Method method) throws ValidationCancelledException, InvalidInputException, ValidationException {
if(!ValidationRuleUtility.isPublic(method)) {
IMessage message = MessageUtility.getUtility().getMessage(vc, IMessagePrefixEjb20Constants.CHKJ2426, IEJBValidationContext.WARNING, bean, clazz, method, this);
vc.addMessage(message);
}
if(method.isFinal()) {
IMessage message = MessageUtility.getUtility().getMessage(vc, IMessagePrefixEjb20Constants.CHKJ2427, IEJBValidationContext.WARNING, bean, clazz, method, this);
vc.addMessage(message);
}
if(method.isStatic()) {
IMessage message = MessageUtility.getUtility().getMessage(vc, IMessagePrefixEjb20Constants.CHKJ2428, IEJBValidationContext.WARNING, bean, clazz, method, this);
vc.addMessage(message);
}
if(!method.isVoid()) {
IMessage message = MessageUtility.getUtility().getMessage(vc, IMessagePrefixEjb20Constants.CHKJ2505_ejbPostCreate, IEJBValidationContext.WARNING, bean, clazz, method, this);
vc.addMessage(message);
}
if(!followRemoteExceptionRules(bean, method)) {
IMessage message = MessageUtility.getUtility().getMessage(vc, IMessagePrefixEjb20Constants.CHKJ2503_ejbPostCreate, IEJBValidationContext.WARNING, bean, clazz, method, this);
vc.addMessage(message);
}
}
public final void validateEjbHomeMethod(IEJBValidationContext vc, EnterpriseBean bean, JavaClass clazz, Method method, List[] methodsExtendedLists) throws ValidationCancelledException, InvalidInputException, ValidationException {
if(!ValidationRuleUtility.isPublic(method)) {
IMessage message = MessageUtility.getUtility().getMessage(vc, IMessagePrefixEjb20Constants.CHKJ2431, IEJBValidationContext.WARNING, bean, clazz, method, this);
vc.addMessage(message);
}
if(method.isStatic()) {
IMessage message = MessageUtility.getUtility().getMessage(vc, IMessagePrefixEjb20Constants.CHKJ2439, IEJBValidationContext.WARNING, bean, clazz, method, this);
vc.addMessage(message);
}
validateRMI_IIOPTypeRules(vc, bean, clazz, method, methodsExtendedLists, true);
if(!followRemoteExceptionRules(bean, method)) {
IMessage message = MessageUtility.getUtility().getMessage(vc, IMessagePrefixEjb20Constants.CHKJ2503_ejbHome, IEJBValidationContext.WARNING, bean, clazz, method, this);
vc.addMessage(message);
}
// "ejbHome" is 7 characters
// method will follow the convention, "ejbHome" + Char.toUpper(0) + substring(1), so reverse that convention here
StringBuffer buffer = new StringBuffer();
buffer.append(Character.toLowerCase(method.getName().charAt(7))); // put the character back into lower-case
buffer.append(method.getName().substring(8)); // substring starts at the character following "ejbHome" and the first character -- substring is 0 indexed
String methodToMatchName = buffer.toString();
Method matchingRemoteHomeMethod = ValidationRuleUtility.getMethod(method, methodToMatchName, getRemoteHomeMethodsExtended(methodsExtendedLists));
if(matchingRemoteHomeMethod != null) {
return;
}
Method matchingLocalHomeMethod = ValidationRuleUtility.getMethod(method, methodToMatchName, getLocalHomeMethodsExtended(methodsExtendedLists));
if(matchingLocalHomeMethod != null) {
return;
}
IMessage message = MessageUtility.getUtility().getMessage(vc, IMessagePrefixEjb20Constants.CHKJ2430, IEJBValidationContext.INFO, bean, clazz, method, new String[]{methodToMatchName}, this);
vc.addMessage(message);
}
public final void validateBusinessMethod(IEJBValidationContext vc, EnterpriseBean bean, JavaClass clazz, Method method, List[] methodsExtendedLists) throws ValidationCancelledException, InvalidInputException, ValidationException {
// IWAD4048 = Business methods must not start with "ejb". Read section 7.10.4 of the EJB 2.0 specification.
// IWAD4201 = This method name must not start with "ejb". Read section 10.6.8 of the EJB 2.0 specification.
// IWAD4317 = The method name must not start with "ejb". Read section 12.2.7 of the EJB 2.0 specification.
if(method.getName().startsWith(IMethodAndFieldConstants.PREFIX_EJB)) {
IMessage message = MessageUtility.getUtility().getMessage(vc, IEJBValidatorMessageConstants.CHKJ2411, IEJBValidationContext.WARNING, bean, clazz, method, this);
vc.addMessage(message);
}
// IWAD4049 = This method must be public. Read section 7.10.4 of the EJB 2.0 specification.
// IWAD4202 = This method must be public. Read section 10.6.8 of the EJB 2.0 specification.
// IWAD4318 = The method must be public. Read section 12.2.7 of the EJB 2.0 specification.
if(!ValidationRuleUtility.isPublic(method)) {
IMessage message = MessageUtility.getUtility().getMessage(vc, IMessagePrefixEjb20Constants.CHKJ2441, IEJBValidationContext.WARNING, bean, clazz, method, this);
vc.addMessage(message);
}
// IWAD4050 = This method must not be final. Read section 7.10.4 of the EJB 2.0 specification.
// IWAD4203 = This method must not be final. Read section 10.6.8 of the EJB 2.0 specification.
// IWAD4319 = The method must not be final. Read section 12.2.7 of the EJB 2.0 specification.
if(method.isFinal()) {
IMessage message = MessageUtility.getUtility().getMessage(vc, IMessagePrefixEjb20Constants.CHKJ2442, IEJBValidationContext.WARNING, bean, clazz, method, this);
vc.addMessage(message);
}
// IWAD4051 = This method must not be static. Read section 7.10.4 of the EJB 2.0 specification.
// IWAD4204 = This method must not be static. Read section 10.6.8 of the EJB 2.0 specification.
// IWAD4320 = The method must not be static. Read section 12.2.7 of the EJB 2.0 specification.
if(method.isStatic()) {
IMessage message = MessageUtility.getUtility().getMessage(vc, IMessagePrefixEjb20Constants.CHKJ2443, IEJBValidationContext.WARNING, bean, clazz, method, this);
vc.addMessage(message);
}
// IWAD4052 = {0} must be a legal RMI-IIOP type. Read section 7.10.4 of the EJB 2.0 specification.
// IWAD4205 = {0} must be a legal RMI-IIOP type. Read section 10.6.8 of the EJB 2.0 specification.
// IWAD4321 = {0} must be a legal type for RMI-IIOP. Read section 12.2.7 of the EJB 2.0 specification.
validateRMI_IIOPTypeRules(vc, bean, clazz, method, methodsExtendedLists, true);
// IWAD4053 = This method cannot throw java.rmi.RemoteException. Read section 7.10.4, 18.3.8, 18.6 of the EJB 2.0 specification.
// IWAD4206 = This method must not throw java.rmi.RemoteException. Read section 10.6.8, 18.3.8, 18.6 of the EJB 2.0 specification.
// IWAD4322 = This method must not throw java.rmi.RemoteException. Read section 12.2.7, 18.3.8, 18.6 of the EJB 2.0 specification.
if(!followRemoteExceptionRules(bean, method)) {
IMessage message = MessageUtility.getUtility().getMessage(vc, IMessagePrefixEjb20Constants.CHKJ2503_bus, getMessageRemoteExceptionSeverity(), bean, clazz, method, this);
vc.addMessage(message);
}
validateMatchingComponentMethod(vc, bean, clazz, method, methodsExtendedLists);
}
public void validateEjbRemoveMethod(IEJBValidationContext vc, EnterpriseBean bean, JavaClass clazz, Method method) throws ValidationCancelledException, InvalidInputException, ValidationException {
// IWAD4402 = This method must be public. Read section 15.7.5 of the EJB 2.0 specification.
if(!ValidationRuleUtility.isPublic(method)) {
IMessage message = MessageUtility.getUtility().getMessage(vc, IMessagePrefixEjb20Constants.CHKJ2492, IEJBValidationContext.WARNING, bean, clazz, method, this);
vc.addMessage(message);
}
// IWAD4403 = This method must not be final. Read section 15.7.5 of the EJB 2.0 specification.
if(method.isFinal()) {
IMessage message = MessageUtility.getUtility().getMessage(vc, IMessagePrefixEjb20Constants.CHKJ2493, IEJBValidationContext.WARNING, bean, clazz, method, this);
vc.addMessage(message);
}
// IWAD4404 = This method must not be static. Read section 15.7.5 of the EJB 2.0 specification.
if(method.isStatic()) {
IMessage message = MessageUtility.getUtility().getMessage(vc, IMessagePrefixEjb20Constants.CHKJ2494, IEJBValidationContext.WARNING, bean, clazz, method, this);
vc.addMessage(message);
}
// IWAD4405 = This method must return void. Read section 15.7.5 of the EJB 2.0 specification.
if(!method.isVoid()) {
IMessage message = MessageUtility.getUtility().getMessage(vc, IMessagePrefixEjb20Constants.CHKJ2505_ejbRemove, IEJBValidationContext.WARNING, bean, clazz, method, this);
vc.addMessage(message);
}
}
/*
* @see IClassVRule#validate(IEJBValidationContext, JavaClass, Field)
*/
public void validate(IEJBValidationContext vc, EnterpriseBean bean, JavaClass clazz, Field field, List[] fieldExtendedLists) throws ValidationCancelledException, InvalidInputException, ValidationException {
// IWAD4024 = A transient field should not be the {0} type. Read section 7.4.1 of the EJB 2.0 specification.
// IWAD4025 = Transient fields are discouraged. Read section 7.4.1 of the EJB 2.0 specification.
// IWAD4115 = {0} must not be defined in this class. Read section 10.3.1 of the EJB 2.0 specification.
// IWAD4259 = <cmp-field> field must be the {0} type. Read section 11.2.1 of the EJB 2.0 specification.
// IWAD4260 = <cmr-field> field must be the {0} type. Read section 11.2.1 of the EJB 2.0 specification.
if(shouldValidateTransientField()) {
validateTransientField(vc, bean, clazz, field);
}
}
public void validateTransientField(IEJBValidationContext vc, EnterpriseBean bean, JavaClass clazz, Field field) throws ValidationCancelledException, InvalidInputException, ValidationException {
// By default do nothing
}
public long getFieldType(EnterpriseBean bean, JavaClass clazz, Field field) {
if(field == null) {
return EXCLUDED_FIELD;
}
else if(field.getName().equals(IMethodAndFieldConstants.FIELDNAME_SERIALVERSIONUID)) {
return SERIALVERSIONUID;
}
else {
return OTHER_FIELD;
}
}
public void validateMatchingMethodExceptions(IEJBValidationContext vc, EnterpriseBean bean, JavaClass clazz, Method method, JavaClass matchingClazz, Method matchingMethod) {
// Every exception thrown on the bean class' method must be thrown on the component/home method
/* Don't check for this here - let the home & component do it.
Set exceptions = ValidationRuleUtility.getNotSubsetExceptions(bean, method, matchingMethod);
Iterator eiterator = exceptions.iterator();
while(eiterator.hasNext()) {
}
*/
// Every exception thrown by the component/home method should be thrown or there may be compile errors
Set exceptions = ValidationRuleUtility.getNotSubsetSubtypeExceptions(bean, matchingMethod, method);
Iterator eiterator = exceptions.iterator();
while(eiterator.hasNext()) {
JavaClass exception = (JavaClass)eiterator.next();
IMessage message = MessageUtility.getUtility().getMessage(vc, IEJBValidatorMessageConstants.CHKJ2456, IEJBValidationContext.WARNING, bean, clazz, method, new String[]{exception.getJavaName(), matchingClazz.getJavaName()}, this);
vc.addMessage(message);
}
}
public final void validateMatchingHomeMethod(IEJBValidationContext vc, EnterpriseBean bean, JavaClass clazz, Method method, List[] methodsExtendedLists) {
Method remoteMethod = ValidationRuleUtility.getMethod(method, getMatchingHomeMethodName(vc, bean, clazz, method, methodsExtendedLists), getRemoteHomeMethodsExtended(methodsExtendedLists));
if(remoteMethod != null) {
validateMatchingMethodExceptions(vc, bean, clazz, method, bean.getHomeInterface(), remoteMethod);
}
Method localMethod = ValidationRuleUtility.getMethod(method, getMatchingHomeMethodName(vc, bean, clazz, method, methodsExtendedLists), getLocalHomeMethodsExtended(methodsExtendedLists));
if(localMethod != null) {
validateMatchingMethodExceptions(vc, bean, clazz, method, bean.getLocalHomeInterface(), localMethod);
}
}
public final void validateMatchingComponentMethod(IEJBValidationContext vc, EnterpriseBean bean, JavaClass clazz, Method method, List[] methodsExtendedLists) {
Method remoteMethod = ValidationRuleUtility.getMethod(method, method.getName(), getRemoteComponentMethodsExtended(methodsExtendedLists));
if(remoteMethod != null) {
validateMatchingMethodExceptions(vc, bean, clazz, method, bean.getRemoteInterface(), remoteMethod);
}
Method localMethod = ValidationRuleUtility.getMethod(method, method.getName(), getLocalComponentMethodsExtended(methodsExtendedLists));
if(localMethod != null) {
validateMatchingMethodExceptions(vc, bean, clazz, method, bean.getLocalInterface(), localMethod);
}
}
protected void validateAppendixB(IEJBValidationContext vc, EnterpriseBean bean, JavaClass thisEjbObject) {
// The Java inheritance structure must match the EJB inheritance structure.
// e.g. if EJB B is a child of EJB A, then class B must be a child of class A.
// B could be a grandchild (or great-grandchild or ...) of A.
if(bean == null) {
return;
}
EnterpriseBean supertype = getSuperType(bean);
JavaClass parentEjbObject = null;
if (supertype != null) {
parentEjbObject = supertype.getEjbClass();
// EJBObject a Xchild of parent EJBObject (X = child, grandchild, great-grandchild, etc.)
try {
ValidationRuleUtility.isValidType(thisEjbObject);
ValidationRuleUtility.isValidType(parentEjbObject);
if (!ValidationRuleUtility.isAssignableFrom(thisEjbObject, parentEjbObject)) {
String[] msgParm = new String[] { thisEjbObject.getQualifiedName(), parentEjbObject.getQualifiedName()};
IMessage message = MessageUtility.getUtility().getMessage(vc, IEJBValidatorMessageConstants.CHKJ2103, IEJBValidationContext.ERROR, bean, thisEjbObject, msgParm, this);
vc.addMessage(message);
}
}
catch (InvalidInputException e) {
String[] msgParm = { e.getJavaClass().getQualifiedName(), bean.getName()};
IMessage message = MessageUtility.getUtility().getMessage(vc, IEJBValidatorMessageConstants.CHKJ2849, IEJBValidationContext.WARNING, bean, msgParm, this);
vc.addMessage(message);
}
}
}
public final boolean followRemoteExceptionRules(EnterpriseBean bean, Method method) throws InvalidInputException, ValidationCancelledException {
// must not throw RemoteException
return ValidationRuleUtility.doesNotThrowRemoteException(bean, method);
}
}