blob: b3b13a6e97fb5a8af2d6abfd88f17fb64867de5b [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2001, 2006 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.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import org.eclipse.jem.java.Field;
import org.eclipse.jem.java.JavaClass;
import org.eclipse.jem.java.JavaHelpers;
import org.eclipse.jem.util.logger.LogEntry;
import org.eclipse.jem.util.logger.proxy.Logger;
import org.eclipse.jst.j2ee.common.CommonPackage;
import org.eclipse.jst.j2ee.common.EjbRef;
import org.eclipse.jst.j2ee.common.EjbRefType;
import org.eclipse.jst.j2ee.common.EnvEntry;
import org.eclipse.jst.j2ee.common.EnvEntryType;
import org.eclipse.jst.j2ee.common.SecurityRole;
import org.eclipse.jst.j2ee.common.SecurityRoleRef;
import org.eclipse.jst.j2ee.ejb.CMPAttribute;
import org.eclipse.jst.j2ee.ejb.ContainerManagedEntity;
import org.eclipse.jst.j2ee.ejb.EJBJar;
import org.eclipse.jst.j2ee.ejb.EjbPackage;
import org.eclipse.jst.j2ee.ejb.EnterpriseBean;
import org.eclipse.jst.j2ee.ejb.Entity;
import org.eclipse.jst.j2ee.ejb.Session;
import org.eclipse.jst.j2ee.ejb.SessionType;
import org.eclipse.jst.j2ee.ejb.TransactionType;
import org.eclipse.wst.validation.internal.core.ValidationException;
import org.eclipse.wst.validation.internal.provisional.core.IMessage;
/**
* This class checks ejb-jar.xml for errors or potential errors.
* If any problems are found, an error, warning, or info marker is added to the task list.
*
* 15.2.5.3 Declaration of security roles referenced from the bean's code
* The Bean Provider is responsible for declaring in the security-role-ref elements of the deploy-ment
* descriptor all the security role names used in the enterprise bean code. Declaring the security roles
* references in the code allows the Application Assembler or Deployer to link the names of the security
* roles used in the code to the security roles defined for an assembled application through the secu-rity-
* role elements.
* The Bean Provider must declare each security role referenced in the code using the secu-rity-
* role-ref element as follows:
* Declare the name of the security role using the role-name element. The name must be the
* security role name that is used as a parameter to the isCallerInRole(String role-Name)
* method.
* Optional: Provide a description of the security role in the description element.
* A security role reference, including the name defined by the role-name element, is scoped to the ses-sion
* or entity bean element whose declaration contains the security-role-ref element.
* The following example illustrates how an enterprise bean's references to security roles are declared in
* the deployment descriptor.
* ...
* <enterprise-beans>
* ...
* <entity>
* <ejb-name>AardvarkPayroll</ejb-name>
* <ejb-class>com.aardvark.payroll.PayrollBean</ejb-class>
* ...
* <security-role-ref>
* <description>
* This security role should be assigned to the
* employees of the payroll department who are
* allowed to update employees' salaries.
* </description>
* <role-name>payroll</role-name>
* </security-role-ref>
* ...
* </entity>
* ...
* </enterprise-beans>
* ...
*
* The deployment descriptor above indicates that the enterprise bean AardvarkPayroll makes the
* security check using isCallerInRole("payroll") in its business method.
*
*
* 15.3.3 Linking security role references to security roles
* If the Application Assembler defines the security-role elements in the deployment descriptor, he
* or she is also responsible for linking all the security role references declared in the secu-rity-
* role-ref elements to the security roles defined in the security-role elements.
* The Application Assembler links each security role reference to a security role using the role-link
* element. The value of the role-link element must be the name of one of the security roles defined in
* a security-role element.
* A role-link element must be used even if the value of role-name is the same as the value of the
* role-link reference.
* The following deployment descriptor example shows how to link the security role reference named
* payroll to the security role named payroll-department.
* ...
* <enterprise-beans>
* ...
* <entity>
* <ejb-name>AardvarkPayroll</ejb-name>
* <ejb-class>com.aardvark.payroll.PayrollBean</ejb-class>
* ...
* <security-role-ref>
* <description>
* This role should be assigned to the
* employees of the payroll department.
* Members of this role have access to
* anyone's payroll record.
*
* The role has been linked to the
* payroll-department role.
* </description>
* <role-name>payroll</role-name>
* <role-link>payroll-department</role-link>
* </security-role-ref>
* ...
* </entity>
* ...
* </enterprise-beans>
* ...
*/
public class EnterpriseBean11VRule extends AValidationRule implements IMessagePrefixEjb11Constants {
private static final Object ID = IValidationRuleList.EJB11_ENTERPRISEBEAN;
private static final Object[] DEPENDS_ON = new Object[]{IValidationRuleList.EJB11_SESSION_BEANCLASS, IValidationRuleList.EJB11_SESSION_HOME, IValidationRuleList.EJB11_SESSION_REMOTE, IValidationRuleList.EJB11_BMP_BEANCLASS, IValidationRuleList.EJB11_BMP_HOME, IValidationRuleList.EJB11_BMP_KEYCLASS, IValidationRuleList.EJB11_BMP_REMOTE, IValidationRuleList.EJB11_CMP_BEANCLASS, IValidationRuleList.EJB11_CMP_HOME, IValidationRuleList.EJB11_CMP_KEYCLASS, IValidationRuleList.EJB11_CMP_REMOTE};
private static final Map MESSAGE_IDS;
private List _securityRoles = null;
static {
MESSAGE_IDS = new HashMap();
MESSAGE_IDS.put(CHKJ2801, new String[]{CHKJ2801 + SPEC});
MESSAGE_IDS.put(CHKJ2802_NAMED, new String[]{CHKJ2802_NAMED + SPEC});
MESSAGE_IDS.put(CHKJ2802_UNNAMED, new String[]{CHKJ2802_UNNAMED + SPEC});
MESSAGE_IDS.put(CHKJ2803_NAMED, new String[]{CHKJ2803_NAMED + SPEC});
MESSAGE_IDS.put(CHKJ2803_UNNAMED, new String[]{CHKJ2803_UNNAMED + SPEC});
MESSAGE_IDS.put(CHKJ2804_NAMED, new String[]{CHKJ2804_NAMED + SPEC});
MESSAGE_IDS.put(CHKJ2804_UNNAMED, new String[]{CHKJ2804_UNNAMED + SPEC});
MESSAGE_IDS.put(CHKJ2806, new String[]{CHKJ2806 + SPEC});
MESSAGE_IDS.put(CHKJ2807, new String[]{CHKJ2807 + SPEC});
MESSAGE_IDS.put(CHKJ2808, new String[]{CHKJ2808 + SPEC});
MESSAGE_IDS.put(CHKJ2809, new String[]{CHKJ2809 + SPEC});
MESSAGE_IDS.put(CHKJ2810_NAMED, new String[]{CHKJ2810_NAMED + SPEC});
MESSAGE_IDS.put(CHKJ2810_UNNAMED, new String[]{CHKJ2810_UNNAMED + SPEC});
MESSAGE_IDS.put(CHKJ2811_NAMED, new String[]{CHKJ2811_NAMED + SPEC});
MESSAGE_IDS.put(CHKJ2811_UNNAMED, new String[]{CHKJ2811_UNNAMED + SPEC});
MESSAGE_IDS.put(CHKJ2812, new String[]{CHKJ2812 + SPEC});
MESSAGE_IDS.put(CHKJ2820, new String[]{CHKJ2820 + SPEC});
MESSAGE_IDS.put(CHKJ2822, new String[]{CHKJ2822 + SPEC});
MESSAGE_IDS.put(CHKJ2823, new String[]{CHKJ2823 + SPEC});
MESSAGE_IDS.put(CHKJ2824, new String[]{CHKJ2824 + SPEC});
MESSAGE_IDS.put(CHKJ2827, new String[]{CHKJ2827 + SPEC});
MESSAGE_IDS.put(CHKJ2828, new String[]{CHKJ2828 + SPEC});
MESSAGE_IDS.put(CHKJ2830, new String[]{CHKJ2830 + SPEC});
MESSAGE_IDS.put(CHKJ2831, new String[]{CHKJ2831 + SPEC});
MESSAGE_IDS.put(CHKJ2832, new String[]{CHKJ2832 + SPEC});
MESSAGE_IDS.put(CHKJ2833, new String[]{CHKJ2833 + SPEC});
MESSAGE_IDS.put(CHKJ2834, new String[]{CHKJ2834 + SPEC});
MESSAGE_IDS.put(CHKJ2835, new String[]{CHKJ2835 + SPEC});
MESSAGE_IDS.put(CHKJ2836, new String[]{CHKJ2836 + SPEC});
MESSAGE_IDS.put(CHKJ2837, new String[]{CHKJ2837 + SPEC});
MESSAGE_IDS.put(CHKJ2838, new String[]{CHKJ2838 + SPEC});
MESSAGE_IDS.put(CHKJ2839, new String[]{CHKJ2839 + SPEC});
MESSAGE_IDS.put(CHKJ2840, new String[]{CHKJ2840 + SPEC});
MESSAGE_IDS.put(CHKJ2841, new String[]{CHKJ2841 + SPEC});
MESSAGE_IDS.put(CHKJ2907, new String[]{CHKJ2907});
MESSAGE_IDS.put(CHKJ2852, new String[]{CHKJ2852});
MESSAGE_IDS.put(CHKJ2908, new String[]{CHKJ2908 + SPEC});
}
public final Map getMessageIds() {
return MESSAGE_IDS;
}
public final Object[] getDependsOn() {
return DEPENDS_ON;
}
public final Object getId() {
return ID;
}
public Object getTarget(Object parent, Object clazz) {
// If called as a dependent, parent will be this EnterpriseBean.
return parent;
}
/**
* 6.5.3 The optional SessionSynchronization interface
*...
* Only a stateful Session bean with container-managed transaction demarcation may
* implement the SessionSynchronization interface.
*...
* There is no need for a Session bean with bean-managed transaction to rely on the
* synchronization call backs because the bean is in control of the commit the bean
* knows when the transaction is about to be committed and it knows the outcome of the
* transaction commit.
*...
*/
public boolean isValidSessionTypeElement(Session session) {
// check syntax
if (!session.isSetSessionType()) {
return false;
}
if (session.getSessionType().getValue() == SessionType.STATEFUL) {
return true;
}
if (session.getSessionType().getValue() == SessionType.STATELESS) {
return true;
}
return false;
}
public boolean isValidTransactionTypeElement(Session sessionBean) {
if (!sessionBean.isSetTransactionType()) {
return false;
}
if (sessionBean.getTransactionType().getValue() == TransactionType.BEAN) {
return true;
}
if (sessionBean.getTransactionType().getValue() == TransactionType.CONTAINER) {
return true;
}
return false;
}
/**
* If the bean components (home interface, remote interface, bean class, and primary
* key) can all be found and reflected, return true. Else, add a validation error
* against the bean, and return false.
*/
public boolean validateBeanComponents(IEJBValidationContext vc, EJBJar ejbJar, EnterpriseBean bean) {
boolean isValid = true;
// Don't need to check if the bean is null, because this method will
// not be called if it is.
try {
ValidationRuleUtility.isValidTypeHierarchy(bean, bean.getEjbClass());
}
catch (InvalidInputException exc) {
if (bean.eIsSet(EjbPackage.eINSTANCE.getEnterpriseBean_EjbClass())) {
IMessage message = MessageUtility.getUtility().getMessage(vc, IEJBValidatorMessageConstants.CHKJ2802_NAMED, IEJBValidationContext.ERROR, bean, new String[] { bean.getEjbClass().getQualifiedName()}, this);
vc.addMessage(message);
}
else {
IMessage message = MessageUtility.getUtility().getMessage(vc, IEJBValidatorMessageConstants.CHKJ2802_UNNAMED, IEJBValidationContext.ERROR, bean, this);
vc.addMessage(message);
}
isValid = false;
}
try {
ValidationRuleUtility.isValidTypeHierarchy(bean, bean.getHomeInterface());
}
catch (InvalidInputException exc) {
if (bean.eIsSet(EjbPackage.eINSTANCE.getEnterpriseBean_HomeInterface())) {
IMessage message = MessageUtility.getUtility().getMessage(vc, IEJBValidatorMessageConstants.CHKJ2803_NAMED, IEJBValidationContext.ERROR, bean, new String[] { bean.getHomeInterfaceName()}, this);
vc.addMessage(message);
}
else {
IMessage message = MessageUtility.getUtility().getMessage(vc, IEJBValidatorMessageConstants.CHKJ2803_UNNAMED, IEJBValidationContext.ERROR, bean, this);
vc.addMessage(message);
}
isValid = false;
}
try {
ValidationRuleUtility.isValidTypeHierarchy(bean, bean.getRemoteInterface());
}
catch (InvalidInputException exc) {
if (bean.eIsSet(EjbPackage.eINSTANCE.getEnterpriseBean_RemoteInterface())) {
IMessage message = MessageUtility.getUtility().getMessage(vc, IEJBValidatorMessageConstants.CHKJ2804_NAMED, IEJBValidationContext.ERROR, bean, new String[] { bean.getRemoteInterfaceName()}, this);
vc.addMessage(message);
}
else {
IMessage message = MessageUtility.getUtility().getMessage(vc, IEJBValidatorMessageConstants.CHKJ2804_UNNAMED, IEJBValidationContext.ERROR, bean, this);
vc.addMessage(message);
}
isValid = false;
}
if (bean.isEntity()) {
JavaClass primaryKey = ((Entity) bean).getPrimaryKey();
try {
ValidationRuleUtility.isValidTypeHierarchy(bean, primaryKey);
}
catch (InvalidInputException exc) {
if (((Entity) bean).eIsSet(EjbPackage.eINSTANCE.getEntity_PrimaryKey())) {
IMessage message = MessageUtility.getUtility().getMessage(vc, IEJBValidatorMessageConstants.CHKJ2810_NAMED, IEJBValidationContext.ERROR, bean, new String[] { ((Entity) bean).getPrimaryKeyName()}, this);
vc.addMessage(message);
}
else {
IMessage message = MessageUtility.getUtility().getMessage(vc, IEJBValidatorMessageConstants.CHKJ2810_UNNAMED, IEJBValidationContext.ERROR, bean, this);
vc.addMessage(message);
}
isValid = false;
}
}
return isValid;
}
public void validateCMPFieldElement(IEJBValidationContext vc, EJBJar ejbJar, EnterpriseBean bean) {
if (bean instanceof ContainerManagedEntity) {
// check syntax of tag is okay
ContainerManagedEntity cmp = (ContainerManagedEntity) bean;
List fields = cmp.getPersistentAttributes();
if ((fields == null) || (fields.size() == 0)) {
IMessage message = MessageUtility.getUtility().getMessage(vc, IEJBValidatorMessageConstants.CHKJ2812, IEJBValidationContext.ERROR, bean, new String[] { bean.getEjbClassName()}, this);
vc.addMessage(message);
return;
}
boolean mapsToMultipleFields = !ValidationRuleUtility.isPrimitivePrimaryKey((ContainerManagedEntity) bean);
Iterator iterator = fields.iterator();
Field field = null;
List fieldNames = new ArrayList(fields.size());
while (iterator.hasNext()) {
CMPAttribute attrib = (CMPAttribute) iterator.next();
if (attrib == null) {
Logger logger = vc.getMsgLogger();
if (logger != null && logger.isLoggingLevel(Level.FINEST)) {
LogEntry entry = vc.getLogEntry();
entry.setSourceID("DDValidator.validateCMPFieldElement(EnterpriseBean)"); //$NON-NLS-1$
entry.setText("CMPAttribute is null."); //$NON-NLS-1$
logger.write(Level.FINEST, entry);
}
continue;
}
field = attrib.getField();
if (field == null) {
if (attrib.getName() != null) {
IMessage message = MessageUtility.getUtility().getMessage(vc, IEJBValidatorMessageConstants.CHKJ2811_NAMED, IEJBValidationContext.ERROR, bean, new String[] { attrib.getName(), bean.getEjbClassName()}, this);
vc.addMessage(message);
}
else {
IMessage message = MessageUtility.getUtility().getMessage(vc, IEJBValidatorMessageConstants.CHKJ2811_UNNAMED, IEJBValidationContext.ERROR, bean, this);
vc.addMessage(message);
}
continue;
}
else if (field.getName().equals(IMethodAndFieldConstants.FIELDNAME_SERIALVERSIONUID)) {
// not a customer-entered field
continue;
}
fieldNames.add(field.getName());
try {
// If the field is not a valid type
ValidationRuleUtility.isValidType(ValidationRuleUtility.getType(field));
}
catch (InvalidInputException exc) {
// field not identified
IMessage message = MessageUtility.getUtility().getMessage(vc, IEJBValidatorMessageConstants.CHKJ2830, IEJBValidationContext.WARNING, bean, new String[] { field.getName()}, this);
vc.addMessage(message);
}
}
// 9.4.7.2
if (mapsToMultipleFields && !ValidationRuleUtility.usesUnknownPrimaryKey(cmp)) {
List primKeyFields = cmp.getPrimaryKey().getFieldsExtended();
// (9.4.7.1 is validated in validatePrimKeyClassElement(bean)
// check if the primary key class' fields exist in the container-managed fields
iterator = primKeyFields.iterator();
while (iterator.hasNext()) {
Field keyField = (Field) iterator.next();
if ((keyField.getName() != null) && (keyField.getName().equals(IMethodAndFieldConstants.FIELDNAME_SERIALVERSIONUID))) {
// not a customer-entered field
continue;
}
if (!fieldNames.contains(keyField.getName())) {
IMessage message = MessageUtility.getUtility().getMessage(vc, IEJBValidatorMessageConstants.CHKJ2831, IEJBValidationContext.WARNING, bean, new String[] { keyField.getName()}, this);
vc.addMessage(message);
}
}
}
}
}
/**
* This validateDeploymentDescriptor is called if the EJBJar could load, which means
* that the syntax of the JAR is (mostly) correct.
*
* EJB spec 1.1, section C.4, "Added the requirement for the Bean Provider to specify whether the
* enterprise bean uses a bean-managed or container-managed transaction."
*/
public void validate(IEJBValidationContext vc, Object targetParent, Object target) {
EJBJar ejbJar = null;
if(targetParent instanceof EnterpriseBean) {
// running as a dependent
ejbJar = (EJBJar)vc.loadModel(EJBValidatorModelEnum.EJB_MODEL);
}
else {
ejbJar = (EJBJar)targetParent;
}
EnterpriseBean bean = (EnterpriseBean)target;
validate(vc, ejbJar, bean);
}
public void validate(IEJBValidationContext vc, EJBJar ejbJar, EnterpriseBean bean) {
if (bean == null) {
IMessage message = MessageUtility.getUtility().getMessage(vc, IMessagePrefixEjb11Constants.CHKJ2908, IEJBValidationContext.WARNING, bean, this);
vc.addMessage(message);
// If bean isn't valid, don't perform any of the other
// validation checks on it.
return;
}
try {
// Check if the class exists, etc.
boolean reflected = validateBeanComponents(vc, ejbJar, bean); // assume everything will reflect properly
validateEnterpriseTypeElement(vc, ejbJar, bean);
validateEJBNameElement(vc, ejbJar, bean);
validateReentrantElement(vc, ejbJar, bean);
validateSessionTypeElement(vc, ejbJar, bean);
validateTransactionTypeElement(vc, ejbJar, bean);
validatePersistenceTypeElement(vc, ejbJar, bean);
validateEnvironmentEntries(vc, ejbJar, bean);
if (!reflected) {
// Something didn't reflect properly, so don't continue with the
// rest of the checks. Some metadata will be nonsense.
return;
}
if (bean.isContainerManagedEntity()) {
ContainerManagedEntity cmp = (ContainerManagedEntity) bean;
if (cmp.getPrimKeyField() != null && !cmp.getPrimKeyField().eIsProxy()) {
// Don't validate the fields if it's neither a primitive primary key nor a compound primary key.
// If the user was attempting a primitive primary key, but did a typo in ejb-jar.xml,
// the user will see a lot of strange messages logged against the fields in the primitive primary key.
validateCMPFieldElement(vc, ejbJar, bean);
}
}
validatePrimKeyClassElement(vc, ejbJar, bean);
validateEJBRef(vc, ejbJar, bean);
validateSecurityRoleRefElement(vc, ejbJar, bean);
}
catch(ValidationCancelledException e) {
throw e;
}
/* unreachable catch block
catch(ValidationException exc) {
// If there's a problem, proceed with the next bean.
IMessage message = MessageUtility.getUtility().getMessage(vc, IEJBValidatorConstants.CHKJ2852, IEJBValidationContext.WARNING, bean, new String[] { bean.getName() }, this);
vc.addMessage(message);
MsgLogger logger = vc.getMsgLogger();
if (logger.isLoggingLevel(Level.FINER)) {
logger.write(Level.FINER, exc);
}
}
*/
catch (Throwable exc) {
// If there's a problem, proceed with the next bean.
IMessage message = MessageUtility.getUtility().getMessage(vc, IEJBValidatorMessageConstants.CHKJ2852, IEJBValidationContext.WARNING, bean, new String[] { bean.getName() }, this);
vc.addMessage(message);
Logger logger = vc.getMsgLogger();
if (logger != null && logger.isLoggingLevel(Level.SEVERE)) {
logger.write(Level.SEVERE, exc);
}
}
}
public void validateEJBNameElement(IEJBValidationContext vc, EJBJar ejbJar, EnterpriseBean bean) {
if (bean == null) {
return;
}
String name = bean.getName();
if ((name == null) || (name.equals(""))) { //$NON-NLS-1$
IMessage message = MessageUtility.getUtility().getMessage(vc, IEJBValidatorMessageConstants.CHKJ2801, IEJBValidationContext.ERROR, bean, this);
vc.addMessage(message);
}
}
/**
* Validate section 14.3 of the EJB 1.1 specification.
*
* 14.3 EJB References
* 14.3.1 Bean Provider's responsibilities
* 14.3.1.1 EJB reference programming interfaces
* 14.3.1.2 Declaration of EJB references in deployment descriptor
* 14.3.2 Application Assembler's responsibilities
* 14.3.3 Deployer's responsibility
* 14.3.4 Container Provider's responsibility
*/
public void validateEJBRef(IEJBValidationContext vc, EJBJar ejbJar, EnterpriseBean bean) {
if (bean == null) {
return;
}
List ejbRefs = bean.getEjbRefs();
if ((ejbRefs == null) || (ejbRefs.size() == 0)) {
return;
}
Iterator iterator = ejbRefs.iterator();
EjbRef ref = null;
while (iterator.hasNext()) {
ref = (EjbRef) iterator.next();
if (ref == null) {
Logger logger = vc.getMsgLogger();
if (logger != null && logger.isLoggingLevel(Level.FINEST)) {
LogEntry entry = vc.getLogEntry();
entry.setSourceID("DDValidator.validateEJBRef(EnterpriseBean)"); //$NON-NLS-1$
entry.setText("EjbRef is null in " + bean.getName()); //$NON-NLS-1$
logger.write(Level.FINEST, entry);
}
continue;
}
// 14.3.1.1
// Info mssg. "EJB spec recommends that all references to other enterprise beans be organized in the ejb subcontext of the bean's environment"
EnterpriseBean namedEjb = null;
if (ref.eIsSet(CommonPackage.eINSTANCE.getEjbRef_Link())) {
// Load the EJB identified by the reference, if it exists.
namedEjb = ejbJar.getEnterpiseBeanFromRef(ref);
if (namedEjb != null) {
// if it's null, let the EAR validator report it
Integer ejbType = new Integer(ref.getType().getValue());
boolean wrongType = false; // is the EJB, identified by ejb-link, of the type specified in the ejb-ref-type element?
String type = (namedEjb instanceof Session) ? "Session" : "Entity"; //$NON-NLS-1$ //$NON-NLS-2$
if (ejbType == null) {
// Neither session nor entity?
wrongType = true;
}
else if (ejbType.intValue() == EjbRefType.SESSION) {
if (!(namedEjb instanceof Session)) {
wrongType = true;
}
}
else if (ejbType.intValue() == EjbRefType.ENTITY) {
if (!(namedEjb instanceof Entity)) {
wrongType = true;
}
}
else {
wrongType = true;
}
if (wrongType) {
String[] parms = { namedEjb.getName(), type };
IMessage message = MessageUtility.getUtility().getMessage(vc, IEJBValidatorMessageConstants.CHKJ2835, IEJBValidationContext.INFO, bean, parms, this);
vc.addMessage(message);
}
}
}
// 14.3.1.2, 14.3.2, 14.3.4
// Check that ejb-ref-name, ejb-ref-type, home, and remote have been defined, and exist
validateHomeRef(vc, ejbJar, ref, namedEjb);
validateRemoteRef(vc, ejbJar, ref, namedEjb);
// 14.3.1.1
// Info mssg. "EJB spec recommends that all references to other enterprise beans be organized in the ejb subcontext of the bean's environment"
if (ref.getName() != null) {
// If ejb name isn't set, that error would have been caught by one of the validateRef methods
// Don't duplicate that effort here.
String ejbName = ref.getName();
if (!ejbName.startsWith("ejb/")) { //$NON-NLS-1$
IMessage message = MessageUtility.getUtility().getMessage(vc, IEJBValidatorMessageConstants.CHKJ2838, IEJBValidationContext.INFO, bean, this);
vc.addMessage(message);
}
}
}
}
public void validateEnterpriseTypeElement(IEJBValidationContext vc, EJBJar ejbJar, EnterpriseBean bean) {
// Attempt in vain to validate the enterprise type element here, because
// if it's not specified, there's a syntax error, and the
// validateDeploymentDescriptor(IReporter, IValidationContext) would have been
// called instead.
/*
if(! (bean.isSession() || bean.isEntity() )) {
// no tag specified
String beanName = (bean.getName() == null) ? "" : bean.getName();
addValidationMessage(IEJBValidationContext.ERROR, IMessagePrefixEjb11Constants.EJB_DD_INVALID_ENTERPRISETYPE, new String[]{beanName}, bean);
}
*/
}
/**
* Validate section 14.3 of the EJB 1.1 specification.
*
* 14.2.1.2 Declaration of environment entries
*/
public void validateEnvironmentEntries(IEJBValidationContext vc, EJBJar ejbJar, EnterpriseBean bean) {
if (bean == null) {
return;
}
List envEntries = bean.getEnvironmentProperties();
if ((envEntries == null) || (envEntries.size() == 0)) {
return;
}
EnvEntry envEntry = null;
Iterator iterator = envEntries.iterator();
DuplicatesTable envNames = new DuplicatesTable();
while (iterator.hasNext()) {
envEntry = (EnvEntry) iterator.next();
if (envEntry == null) {
Logger logger = vc.getMsgLogger();
if (logger != null && logger.isLoggingLevel(Level.FINEST)) {
LogEntry entry = vc.getLogEntry();
entry.setSourceID("DDValidator.validateEnvironmentEntries(EnterpriseBean)"); //$NON-NLS-1$
entry.setText("EjbEntry is null in " + bean.getName()); //$NON-NLS-1$
logger.write(Level.FINEST, entry);
}
continue;
}
if (envEntry.getName() != null) {
envNames.add(envEntry.getName());
}
else {
IMessage message = MessageUtility.getUtility().getMessage(vc, IEJBValidatorMessageConstants.CHKJ2839, IEJBValidationContext.WARNING, bean, this);
vc.addMessage(message);
}
if (envEntry.isSetType()) {
// 14.2.1.2; type must be one of these types: String, Integer, Boolean, Double, Byte, Short, Long, and Float.
int type = envEntry.getType().getValue();
if (!((type == EnvEntryType.BOOLEAN) || (type == EnvEntryType.BYTE) || (type == EnvEntryType.DOUBLE) || (type == EnvEntryType.FLOAT) || (type == EnvEntryType.INTEGER) || (type == EnvEntryType.LONG) || (type == EnvEntryType.SHORT) || (type == EnvEntryType.STRING))) {
IMessage message = MessageUtility.getUtility().getMessage(vc, IEJBValidatorMessageConstants.CHKJ2840, IEJBValidationContext.WARNING, bean, this);
vc.addMessage(message);
}
}
else {
IMessage message = MessageUtility.getUtility().getMessage(vc, IEJBValidatorMessageConstants.CHKJ2840, IEJBValidationContext.WARNING, bean, this);
vc.addMessage(message);
}
}
if (envNames.containsDuplicates()) {
Iterator dups = envNames.getDuplicates().iterator();
while (dups.hasNext()) {
String name = (String) dups.next();
IMessage message = MessageUtility.getUtility().getMessage(vc, IEJBValidatorMessageConstants.CHKJ2841, IEJBValidationContext.WARNING, bean, new String[] { name }, this);
vc.addMessage(message);
}
}
}
/**
* If the metadata from the EjbRef is not valid, add a validation message.
*
* @parm EjbRef The <ejb-ref> element this method validates.
* @parm EnterpriseBean If the <ejb-ref> uses an <ejb-link>, this is the enterprise bean identified by that link. If the link doesn't exist, or if the user has identified a bean which doesn't exist, this parameter will be null.
*/
protected void validateHomeRef(IEJBValidationContext vc, EJBJar ejbJar, EjbRef ref, EnterpriseBean namedEjb) {
boolean validType = true;
EnterpriseBean bean = (EnterpriseBean)ref.eContainer();
if (ref.eIsSet(CommonPackage.eINSTANCE.getEjbRef_Home())) {
try {
String homeName = ref.getHome();
JavaHelpers type = ValidationRuleUtility.getType(homeName, bean);
// Check that the home specified in the <home> element of the <ejb-ref> element
// exists.
ValidationRuleUtility.isValidType(type);
if (namedEjb != null) {
// Check that the home specified in the <home> element
// is assignable to the home used by the named EJB in the
// <ejb-link> element.
JavaClass intfType = namedEjb.getHomeInterface();
ValidationRuleUtility.isValidType(intfType);
// Make sure that the identified home/remote interface in the ejb-ref
// is of the same type as the one used by the bean.
if (!ValidationRuleUtility.isAssignableFrom(type.getWrapper(), intfType)) {
String[] parms = { namedEjb.getName(), intfType.getName()};
IMessage message = MessageUtility.getUtility().getMessage(vc, IEJBValidatorMessageConstants.CHKJ2836, IEJBValidationContext.INFO, bean, parms, this);
vc.addMessage(message);
}
}
}
catch (InvalidInputException exc) {
validType = false;
}
}
else {
validType = false;
}
if (!validType) {
String[] parms = { ref.getHome()};
IMessage message = MessageUtility.getUtility().getMessage(vc, IEJBValidatorMessageConstants.CHKJ2832, IEJBValidationContext.INFO, bean, parms, this);
vc.addMessage(message);
}
}
public void validatePersistenceTypeElement(IEJBValidationContext vc, EJBJar ejbJar, EnterpriseBean bean) {
// Attempt in vain to validate the persistence type element here, because
// if it's not specified, there's a syntax error, and the
// validateDeploymentDescriptor(IReporter, IValidationContext) would have been
// called instead.
if (bean.isEntity()) {
// check syntax
Entity entityBean = (Entity) bean;
if (!(entityBean.isContainerManagedEntity() || entityBean.isBeanManagedEntity())) {
IMessage message = MessageUtility.getUtility().getMessage(vc, IEJBValidatorMessageConstants.CHKJ2809, IEJBValidationContext.ERROR, bean, this);
vc.addMessage(message);
}
}
}
/**
* If the primary key class reflected properly, return true. Else, return false.
*/
public void validatePrimKeyClassElement(IEJBValidationContext vc, EJBJar ejbJar, EnterpriseBean bean) {
if (bean.isEntity()) {
// check syntax
if (bean instanceof ContainerManagedEntity) {
ContainerManagedEntity cmp = (ContainerManagedEntity) bean;
JavaClass clas = cmp.getPrimaryKey();
if (clas != null && !clas.eIsProxy() && !isValidPrimKeyField(cmp,clas)) {
// 9.4.7.1
// user has specified both a prim-key-class and a primkey-field
// can't use the CMPAttribute's field's name, because the primitive primary key returned is null
IMessage message = MessageUtility.getUtility().getMessage(vc, IEJBValidatorMessageConstants.CHKJ2828, IEJBValidationContext.ERROR, bean, this);
vc.addMessage(message);
}
}
}
}
/**
* If the primary key is specified in the xml, answer whether it is the same as the derived primaryKeyAttribute
*/
public static boolean isValidPrimKeyField(ContainerManagedEntity cmp, JavaClass clas) {
return cmp.getPrimaryKeyName().equals(clas.getJavaName());
}
public void validateReentrantElement(IEJBValidationContext vc, EJBJar ejbJar, EnterpriseBean bean) {
if (bean.isEntity()) {
// check syntax
Entity entity = (Entity) bean;
if (!entity.isSetReentrant()) {
// Can only test if the reentrant attribute is set, because the model defaults it
// to some boolean value if it isn't set.
IMessage message = MessageUtility.getUtility().getMessage(vc, IEJBValidatorMessageConstants.CHKJ2806, IEJBValidationContext.ERROR, bean, this);
vc.addMessage(message);
}
}
}
/**
* If the metadata from the EjbRef is not valid, add a validation message.
*
* @parm EjbRef The ref whose home this method checks.
* @parm EnterpriseBean If the EjbRef uses an <ejb-link> element, this is the enterprise bean identified by that element. It may be null, if the user has made a mistake.
*/
protected void validateRemoteRef(IEJBValidationContext vc, EJBJar ejbJar, EjbRef ref, EnterpriseBean namedEjb) {
boolean validType = true;
EnterpriseBean bean = (EnterpriseBean)ref.eContainer();
if (ref.eIsSet(CommonPackage.eINSTANCE.getEjbRef_Remote())) {
try {
String remoteName = ref.getRemote();
JavaHelpers type = ValidationRuleUtility.getType(remoteName, bean);
// Check that the home specified in the <home> element of the <ejb-ref> element
// exists.
ValidationRuleUtility.isValidType(type);
if (namedEjb != null) {
// Check that the home specified in the <home> element
// is assignable to the home used by the named EJB in the
// <ejb-link> element.
JavaClass intfType = namedEjb.getRemoteInterface();
ValidationRuleUtility.isValidType(intfType);
// Make sure that the identified home/remote interface in the ejb-ref
// is of the same type as the one used by the bean.
if (!ValidationRuleUtility.isAssignableFrom(type.getWrapper(), intfType)) {
String[] parms = { namedEjb.getName(), intfType.getName()};
IMessage message = MessageUtility.getUtility().getMessage(vc, IEJBValidatorMessageConstants.CHKJ2837, IEJBValidationContext.INFO, bean, parms, this);
vc.addMessage(message);
}
}
}
catch (InvalidInputException exc) {
validType = false;
}
}
else {
validType = false;
}
if (!validType) {
String[] parms = { ref.getRemote()};
IMessage message = MessageUtility.getUtility().getMessage(vc, IEJBValidatorMessageConstants.CHKJ2833, IEJBValidationContext.INFO, bean, parms, this);
vc.addMessage(message);
}
}
/**
* 15.2.5.3 Declaration of security roles referenced from the bean's code
* The Bean Provider is responsible for declaring in the security-role-ref
* elements of the deployment descriptor all the security role names used
* in the enterprise bean code. Declaring the security roles references in
* the code allows the Application Assembler or Deployer to link the names
* of the security roles used in the code to the security roles defined for
* an assembled application through the security-role elements.
* The Bean Provider must declare each security role referenced in the code
* using the security-role-ref element as follows:
* Declare the name of the security role using the role-name element.
* The name must be the security role name that is used as a parameter to
* the isCallerInRole(String role-Name) method.
* Optional: Provide a description of the security role in the
* description element. A security role reference, including the name defined
* by the role-name element, is scoped to the session or entity bean element
* whose declaration contains the security-role-ref element. The following
* example illustrates how an enterprise bean's references to security roles
* are declared in the deployment descriptor.
* ...
* <enterprise-beans>
* ...
* <entity>
* <ejb-name>AardvarkPayroll</ejb-name>
* <ejb-class>com.aardvark.payroll.PayrollBean</ejb-class>
* ...
* <security-role-ref>
* <description>
* This security role should be assigned to the
* employees of the payroll department who are
* allowed to update employees' salaries.
* </description>
* <role-name>payroll</role-name>
* </security-role-ref>
* ...
* </entity>
* ...
* </enterprise-beans>
* ...
*
* The deployment descriptor above indicates that the enterprise bean
* AardvarkPayroll makes the security check using isCallerInRole("payroll")
* in its business method.
*
*
* 15.3.3 Linking security role references to security roles
* If the Application Assembler defines the security-role elements in the
* deployment descriptor, he or she is also responsible for linking all the
* security role references declared in the security-role-ref elements to the
* security roles defined in the security-role elements. The Application
* Assembler links each security role reference to a security role using the
* role-link element. The value of the role-link element must be the name of
* one of the security roles defined in a security-role element.
* A role-link element must be used even if the value of role-name is the
* same as the value of the role-link reference.
* The following deployment descriptor example shows how to link the security
* role reference named payroll to the security role named payroll-department.
* ...
* <enterprise-beans>
* ...
* <entity>
* <ejb-name>AardvarkPayroll</ejb-name>
* <ejb-class>com.aardvark.payroll.PayrollBean</ejb-class>
* ...
* <security-role-ref>
* <description>
* This role should be assigned to the
* employees of the payroll department.
* Members of this role have access to
* anyone's payroll record.
*
* The role has been linked to the
* payroll-department role.
* </description>
* <role-name>payroll</role-name>
* <role-link>payroll-department</role-link>
* </security-role-ref>
* ...
* </entity>
* ...
* </enterprise-beans>
* ...
*
*/
public void validateSecurityRoleRefElement(IEJBValidationContext vc, EJBJar ejbJar, EnterpriseBean bean) {
if (bean == null) {
return;
}
/**
* Need to build up a list of duplicate role names, but the validation message
* needs to be registered against the duplicate SecurityRoleRef instance.
* (Without the instance, we cannot get line numbers.)
*
* This class wrappers the SecurityRolRef instance so that the wrapper's
* implemention of equals compares the names, but the validation message will
* still be able to get the ref from the duplicate name.
*/
class RoleRefWrapper {
private SecurityRoleRef _ref = null;
public RoleRefWrapper(SecurityRoleRef ref) {
_ref = ref;
}
public boolean equals(Object o) {
if (o instanceof RoleRefWrapper) {
RoleRefWrapper other = (RoleRefWrapper) o;
return _ref.getName().equals(other.getRoleRef().getName());
}
return false;
}
public SecurityRoleRef getRoleRef() {
return _ref;
}
}
boolean areSRolesDefined = ((_securityRoles != null) && (_securityRoles.size() > 0));
List securityRoleRefs = bean.getSecurityRoleRefs();
if ((securityRoleRefs != null) && (securityRoleRefs.size() != 0)) {
// Check that each security role ref refers to a security role,
// if security roles are defined in the assembly descriptor,
// and that each referenced security role exists.
DuplicatesTable roleRefNames = new DuplicatesTable();
for (int i = 0; i < securityRoleRefs.size(); i++) {
SecurityRoleRef ref = (SecurityRoleRef) securityRoleRefs.get(i);
// Check that the role name is set (15.2.5.3)
String roleName = ref.getName();
if ((roleName == null) || (roleName.equals(""))) { //$NON-NLS-1$
roleName = ""; //$NON-NLS-1$
String beanName = (bean.getName() == null) ? "" : bean.getName(); //$NON-NLS-1$
IMessage message = MessageUtility.getUtility().getMessage(vc, IEJBValidatorMessageConstants.CHKJ2822, IEJBValidationContext.WARNING, ref, new String[] { beanName }, this);
vc.addMessage(message);
}
else {
// Build up the list of names, to check for duplicates
roleRefNames.add(new RoleRefWrapper(ref));
}
// Check that the role link is set (15.3.3)
String roleLink = ref.getLink();
boolean isLinkDefined = ((ref.eIsSet(CommonPackage.eINSTANCE.getSecurityRoleRef_Link())) && (roleLink != null) && (!roleLink.equals(""))); //$NON-NLS-1$
if ((areSRolesDefined) && (!isLinkDefined)) {
// must have role link defined (15.3.3)
IMessage message = MessageUtility.getUtility().getMessage(vc, IEJBValidatorMessageConstants.CHKJ2823, IEJBValidationContext.WARNING, ref, this);
vc.addMessage(message);
}
else if ((!areSRolesDefined) && (isLinkDefined)) {
// must not have role link defined (15.2.5.3)
IMessage message = MessageUtility.getUtility().getMessage(vc, IEJBValidatorMessageConstants.CHKJ2827, IEJBValidationContext.WARNING, ref, this);
vc.addMessage(message);
}
else if (areSRolesDefined && isLinkDefined) {
// check that the role listed in the link exists. (15.3.3)
Iterator iterator = _securityRoles.iterator();
boolean roleExists = false;
while(iterator.hasNext()) {
SecurityRole role = (SecurityRole)iterator.next();
if(role.getRoleName().equals(roleLink)) {
roleExists = true;
break;
}
}
if (!roleExists) {
IMessage message = MessageUtility.getUtility().getMessage(vc, IEJBValidatorMessageConstants.CHKJ2824, IEJBValidationContext.WARNING, ref, new String[] { roleName }, this);
vc.addMessage(message);
}
}
}
// Check for duplicates
// Check that there are no duplicate role-names. (15.3.1)
if (roleRefNames.containsDuplicates()) {
List duplicates = roleRefNames.getDuplicates();
Iterator iterator = duplicates.iterator();
while (iterator.hasNext()) {
IMessage message = MessageUtility.getUtility().getMessage(vc, IEJBValidatorMessageConstants.CHKJ2820, IEJBValidationContext.WARNING, ((RoleRefWrapper) iterator.next()).getRoleRef(), this);
vc.addMessage(message);
}
}
roleRefNames.clear();
}
}
/**
* 6.5.3 The optional SessionSynchronization interface
*...
* Only a stateful Session bean with container-managed transaction demarcation may
* implement the SessionSynchronization interface.
*...
* There is no need for a Session bean with bean-managed transaction to rely on the
* synchronization call backs because the bean is in control of the commit the bean
* knows when the transaction is about to be committed and it knows the outcome of the
* transaction commit.
*...
*/
public void validateSessionTypeElement(IEJBValidationContext vc, EJBJar ejbJar, EnterpriseBean bean) {
if (bean.isSession()) {
Session session = (Session) bean;
// check syntax
boolean isValidSess = isValidSessionTypeElement(session);
if (!isValidSess) {
IMessage message = MessageUtility.getUtility().getMessage(vc, IEJBValidatorMessageConstants.CHKJ2807, IEJBValidationContext.ERROR, session, this);
vc.addMessage(message);
}
}
}
public void validateTransactionTypeElement(IEJBValidationContext vc, EJBJar ejbJar, EnterpriseBean bean) {
if (bean.isSession()) {
// check syntax
Session sessionBean = (Session) bean;
if (!isValidTransactionTypeElement(sessionBean)) {
IMessage message = MessageUtility.getUtility().getMessage(vc, IEJBValidatorMessageConstants.CHKJ2808, IEJBValidationContext.ERROR, bean, this);
vc.addMessage(message);
}
}
}
/*
* @see IValidationRule#reset()
*/
public void reset() {
super.reset();
_securityRoles = null;
}
/*
* @see IValidationRule#preValidate(IEJBValidationContext, Object, Object)
*/
public void preValidate(IEJBValidationContext vc, Object targetParent, Object target) throws ValidationCancelledException, ValidationException {
super.preValidate(vc, targetParent, target);
EJBJar ejbJar = (EJBJar)vc.loadModel(EJBValidatorModelEnum.EJB_MODEL);
if(ejbJar == null) {
return;
}
if(ejbJar.getAssemblyDescriptor() == null) {
return;
}
_securityRoles = ejbJar.getAssemblyDescriptor().getSecurityRoles();
}
}