| /******************************************************************************* |
| * 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.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.logging.Level; |
| |
| import org.eclipse.jem.java.Method; |
| 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.SecurityRole; |
| import org.eclipse.jst.j2ee.ejb.AssemblyDescriptor; |
| import org.eclipse.jst.j2ee.ejb.EJBJar; |
| import org.eclipse.jst.j2ee.ejb.EnterpriseBean; |
| import org.eclipse.jst.j2ee.ejb.MethodElement; |
| import org.eclipse.jst.j2ee.ejb.MethodPermission; |
| import org.eclipse.jst.j2ee.ejb.MethodTransaction; |
| import org.eclipse.jst.j2ee.internal.J2EEConstants; |
| 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 EJBJar11VRule extends AValidationRule implements IMessagePrefixEjb11Constants { |
| private DuplicatesTable _ejbName = null; |
| private static final Object ID = IValidationRuleList.EJB11_EJBJAR; |
| private static final Object[] DEPENDS_ON = new Object[]{IValidationRuleList.EJB11_SESSION_BEANCLASS, IValidationRuleList.EJB11_SESSION_REMOTE, IValidationRuleList.EJB11_SESSION_HOME, IValidationRuleList.EJB11_CMP_BEANCLASS, IValidationRuleList.EJB11_CMP_REMOTE, IValidationRuleList.EJB11_CMP_HOME, IValidationRuleList.EJB11_CMP_KEYCLASS, IValidationRuleList.EJB11_BMP_BEANCLASS, IValidationRuleList.EJB11_BMP_REMOTE, IValidationRuleList.EJB11_BMP_HOME, IValidationRuleList.EJB11_BMP_KEYCLASS, IValidationRuleList.EJB11_EJBEXT}; |
| |
| private static final Map MESSAGE_IDS; |
| |
| static { |
| MESSAGE_IDS = new HashMap(); |
| |
| MESSAGE_IDS.put(CHKJ2814, new String[]{CHKJ2814 + SPEC}); |
| |
| MESSAGE_IDS.put(CHKJ2825, new String[]{CHKJ2825 + SPEC}); |
| MESSAGE_IDS.put(CHKJ2826, new String[]{CHKJ2826 + SPEC}); |
| |
| MESSAGE_IDS.put(CHKJ2842, new String[]{CHKJ2842 + SPEC}); |
| MESSAGE_IDS.put(CHKJ2843, new String[]{CHKJ2843 + SPEC}); |
| MESSAGE_IDS.put(CHKJ2844, new String[]{CHKJ2844 + SPEC}); |
| MESSAGE_IDS.put(CHKJ2845, new String[]{CHKJ2845 + SPEC}); |
| MESSAGE_IDS.put(CHKJ2846, new String[]{CHKJ2846 + SPEC}); |
| MESSAGE_IDS.put(CHKJ2847, new String[]{CHKJ2847 + SPEC}); |
| |
| MESSAGE_IDS.put(CHKJ2850, new String[]{CHKJ2850 + SPEC}); |
| MESSAGE_IDS.put(CHKJ2852, new String[]{CHKJ2852}); |
| |
| MESSAGE_IDS.put(CHKJ2875, new String[]{CHKJ2875 + SPEC}); |
| |
| MESSAGE_IDS.put(CHKJ2895, new String[]{CHKJ2895 + SPEC}); |
| } |
| |
| public EJBJar11VRule() { |
| _ejbName = new DuplicatesTable(); |
| } |
| |
| 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 target) { |
| return null; |
| } |
| |
| /** |
| * 15.3.1 Security roles |
| * The Application Assembler can define one or more security roles in |
| * the deployment descriptor. The Application Assembler then assigns |
| * groups of methods of the enterprise beans' home and remote interfaces |
| * to the security roles to define the security view of the application. |
| * Because the Application Assembler does not, in general, know the |
| * security environment of the operational environment, the security |
| * roles are meant to be logical roles (or actors), each representing |
| * a type of user that should have the same access rights to the |
| * application. The Deployer then assigns user groups and/or user |
| * accounts defined in the operational environment to the security roles |
| * defined by the Application Assembler. |
| * Defining the security roles in the deployment descriptor is optional [17] |
| * for the Application Assembler. Their omission in the deployment |
| * descriptor means that the Application Assembler chose not to pass any |
| * security deployment related instructions to the Deployer in the |
| * deployment descriptor. The Application Assembler is responsible for |
| * the following: |
| * - Define each security role using a security-role element. |
| * - Use the role-name element to define the name of the security role. |
| * - Optionally, use the description element to provide a description of |
| * a security role. |
| * The security roles defined by the security-role elements are scoped to |
| * the ejb-jar file level, and apply to all the enterprise beans in the |
| * ejb-jar file. |
| * [17] If the Application Assembler does not define security roles in the |
| * deployment descriptor, the Deployer will have to define security |
| * roles at deployment time. |
| *... |
| */ |
| protected void validateAssemblyDescriptorElement(IEJBValidationContext vc, EJBJar ejbJar) { |
| vc.terminateIfCancelled(); |
| |
| // Validate the security roles, if they're defined in the assembly-descriptor. |
| if (ejbJar == null) { |
| // nothing to validate |
| return; |
| } |
| |
| /** |
| * Need to build up a list of duplicate role names, but the validation message |
| * needs to be registered against the duplicate SecurityRole instance. |
| * (Without the instance, we cannot get line numbers.) |
| * |
| * This class wrappers the SecurityRol 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 RoleWrapper { |
| private SecurityRole _role = null; |
| |
| public RoleWrapper(SecurityRole role) { |
| _role = role; |
| } |
| |
| public boolean equals(Object o) { |
| if (o instanceof RoleWrapper) { |
| RoleWrapper other = (RoleWrapper) o; |
| return _role.getRoleName().equals(other.getRole().getRoleName()); |
| } |
| return false; |
| } |
| |
| public SecurityRole getRole() { |
| return _role; |
| } |
| } |
| |
| AssemblyDescriptor assemblyDescriptor = ejbJar.getAssemblyDescriptor(); |
| if (assemblyDescriptor == null) { |
| // nothing to validate |
| return; |
| } |
| |
| List roles = assemblyDescriptor.getSecurityRoles(); |
| if (roles != null) { |
| DuplicatesTable roleNames = new DuplicatesTable(); |
| SecurityRole role = null; |
| Iterator roleIt = roles.iterator(); |
| while (roleIt.hasNext()) { |
| vc.terminateIfCancelled(); |
| // Check that the role-name element has been set |
| role = (SecurityRole) roleIt.next(); |
| if (role == null) { |
| // role-name not set |
| IMessage message = MessageUtility.getUtility().getMessage(vc, IEJBValidatorMessageConstants.CHKJ2825, IEJBValidationContext.WARNING, ejbJar, this); |
| vc.addMessage(message); |
| } |
| else if ((!role.eIsSet(CommonPackage.eINSTANCE.getSecurityRole_RoleName())) || (role.getRoleName().equals(""))) { //$NON-NLS-1$ |
| // role-name not set |
| IMessage message = MessageUtility.getUtility().getMessage(vc, IEJBValidatorMessageConstants.CHKJ2825, IEJBValidationContext.WARNING, role, this); |
| vc.addMessage(message); |
| } |
| else { |
| // Build up hashtable to check for duplicate role-names. |
| roleNames.add(new RoleWrapper(role)); |
| } |
| } |
| |
| // Check that there are no duplicate role-names. (15.3.1) |
| if (roleNames.containsDuplicates()) { |
| List duplicates = roleNames.getDuplicates(); |
| Iterator iterator = duplicates.iterator(); |
| while (iterator.hasNext()) { |
| IMessage message = MessageUtility.getUtility().getMessage(vc, IEJBValidatorMessageConstants.CHKJ2826, IEJBValidationContext.WARNING, ((RoleWrapper) iterator.next()).getRole(), this); |
| vc.addMessage(message); |
| } |
| } |
| roleNames.clear(); |
| } |
| |
| List methTrans = assemblyDescriptor.getMethodTransactions(); |
| MethodTransaction mt = null; |
| Iterator iterator = methTrans.iterator(); |
| while (iterator.hasNext()) { |
| vc.terminateIfCancelled(); |
| |
| try { |
| mt = (MethodTransaction) iterator.next(); |
| } |
| catch (Throwable exc) { |
| Logger logger = vc.getMsgLogger(); |
| if (logger != null && logger.isLoggingLevel(Level.FINER)) { |
| logger.write(Level.FINER, exc); |
| } |
| mt = null; |
| } |
| |
| if (mt == null) { |
| Logger logger = vc.getMsgLogger(); |
| if (logger != null && logger.isLoggingLevel(Level.FINEST)) { |
| LogEntry entry = vc.getLogEntry(); |
| entry.setSourceID("DDValidator.validateAssemblyDescriptorElement"); //$NON-NLS-1$ |
| entry.setText("mt is null"); //$NON-NLS-1$ |
| logger.write(Level.FINEST, entry); |
| } |
| continue; |
| } |
| |
| boolean hasValidMethod = validateMethodElements(vc, ejbJar, mt.getMethodElements()); |
| if (!hasValidMethod) { |
| IMessage message = MessageUtility.getUtility().getMessage(vc, IEJBValidatorMessageConstants.CHKJ2847, IEJBValidationContext.WARNING, mt, this); |
| vc.addMessage(message); |
| } |
| } |
| |
| List methodPermissions = assemblyDescriptor.getMethodPermissions(); |
| iterator = methodPermissions.iterator(); |
| while (iterator.hasNext()) { |
| MethodPermission mp = (MethodPermission) iterator.next(); |
| |
| boolean hasValidMethod = validateMethodElements(vc, ejbJar, mp.getMethodElements()); |
| if (!hasValidMethod) { |
| // 15.3.2, p. 229, a <method-permission> must have at least one method listed (and that method must be found) |
| IMessage message = MessageUtility.getUtility().getMessage(vc, IEJBValidatorMessageConstants.CHKJ2846, IEJBValidationContext.WARNING, mp, this); |
| vc.addMessage(message); |
| } |
| |
| // at least one security-role must be defined |
| List mproles = mp.getRoles(); |
| if ((mproles == null) || (mproles.size() == 0)) { |
| IMessage message = MessageUtility.getUtility().getMessage(vc, IEJBValidatorMessageConstants.CHKJ2845, IEJBValidationContext.WARNING, mp, 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) throws ValidationException { |
| EJBJar ejbJar = (EJBJar) target; |
| List enterpriseBeans = ejbJar.getEnterpriseBeans(); |
| Iterator iterator = enterpriseBeans.iterator(); |
| EnterpriseBean bean = null; |
| String beanName = null; |
| while (iterator.hasNext()) { |
| try { |
| bean = (EnterpriseBean) iterator.next(); |
| register(vc, ejbJar, bean); |
| |
| Object id = IValidationRuleList.EJB11_ENTERPRISEBEAN; |
| IValidationRule vRule = EJBValidationRuleFactory.getFactory().getRule(vc, id); |
| if (vRule == null) { |
| // This has already been logged by the AbstractEJBValidationRuleFactory, so just |
| // need to add "Cannot validate" to the task list. |
| continue; |
| } |
| try { |
| vRule.preValidate(vc, ejbJar, bean); |
| vRule.validate(vc, ejbJar, bean); |
| vRule.postValidate(vc, ejbJar, bean); |
| } |
| catch (ValidationCancelledException exc) { |
| // Clean up the messages which are on the task list? Or is it nicer to leave them behind? |
| } |
| catch(ValidationException e) { |
| throw e; |
| } |
| catch (Throwable exc) { |
| addInternalErrorMessage(vc, exc); |
| } |
| finally { |
| EJBValidationRuleFactory.getFactory().release(vRule); |
| } |
| } |
| catch(ValidationCancelledException e) { |
| throw e; |
| } |
| catch (ValidationException e) { |
| throw e; |
| } |
| 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[] { J2EEConstants.EJBJAR_DD_SHORT_NAME, beanName }, this); |
| vc.addMessage(message); |
| Logger logger = vc.getMsgLogger(); |
| if (logger != null && logger.isLoggingLevel(Level.SEVERE)) { |
| logger.write(Level.SEVERE, exc); |
| } |
| } |
| } |
| |
| // Since the assembly descriptor is not specific to a bean, validate it once, after all bean processing is complete. |
| validateAssemblyDescriptorElement(vc, ejbJar); |
| validateUniqueEjbNames(vc, ejbJar); |
| validateClientJAR(vc, ejbJar); |
| } |
| |
| public void reset() { |
| super.reset(); |
| _ejbName.clear(); |
| } |
| |
| protected void register(IEJBValidationContext vc, EJBJar ejbJar, EnterpriseBean bean) { |
| // To check if every bean name is unique, need to build a list |
| _ejbName.add(new EjbNameWrapper(bean)); |
| } |
| |
| private void addInternalErrorMessage(IEJBValidationContext vc, Throwable exc) { |
| IMessage mssg = vc.getMessage(); |
| mssg.setId(IEJBValidatorMessageConstants.CHKJ2900); |
| vc.addMessage(mssg); |
| |
| if(exc != null) { |
| Logger logger = vc.getMsgLogger(); |
| if (logger != null && logger.isLoggingLevel(Level.SEVERE)) { |
| logger.write(Level.SEVERE, exc); |
| } |
| } |
| } |
| |
| public void validateUniqueEjbNames(IEJBValidationContext vc, EJBJar ejbJar) { |
| List names = _ejbName.getDuplicates(); |
| if(names.size() == 0) { |
| return; |
| } |
| |
| Iterator iterator = names.iterator(); |
| while(iterator.hasNext()) { |
| EjbNameWrapper wrapper = (EjbNameWrapper)iterator.next(); |
| IMessage message = MessageUtility.getUtility().getMessage(vc, IEJBValidatorMessageConstants.CHKJ2895, IEJBValidationContext.WARNING, wrapper.getBean(), new String[]{wrapper.getBean().getName()}, this); |
| vc.addMessage(message); |
| } |
| } |
| |
| protected void validateClientJAR(IEJBValidationContext vc, EJBJar ejbJar) { |
| String clientJARName = ejbJar.getEjbClientJar(); |
| if(clientJARName == null) { |
| // No client JAR specified; everything's okay. |
| return; |
| } |
| |
| Boolean exists = (Boolean)vc.loadModel(EJBValidatorModelEnum.EJB_CLIENTJAR, new Object[]{clientJARName}); |
| if(exists == null) { |
| // Helper doesn't support load model. WAS? |
| // Can't perform this check, so just return. |
| return; |
| } |
| |
| if(!exists.booleanValue()) { |
| IMessage message = MessageUtility.getUtility().getMessage(vc, IEJBValidatorMessageConstants.CHKJ2875, IEJBValidationContext.ERROR, ejbJar, new String[]{clientJARName}, this); |
| vc.addMessage(message); |
| } |
| } |
| |
| /** |
| * Both section 11.4.1 and 15.3.2 need the <method> element. Also refer |
| * to 16.5 for syntax. |
| * |
| * Return true if at least one of the methods referenced by this list of |
| * MethodElement can be found. |
| */ |
| protected boolean validateMethodElements(IEJBValidationContext vc, EJBJar ejbJar, List elements) { |
| if ((elements == null) || (elements.size() == 0)) { |
| return false; |
| } |
| |
| boolean hasValidMethod = false; |
| Iterator iterator = elements.iterator(); |
| while (iterator.hasNext()) { |
| vc.terminateIfCancelled(); |
| MethodElement element = (MethodElement) iterator.next(); |
| |
| EnterpriseBean bean = element.getEnterpriseBean(); |
| if (bean == null) { |
| IMessage message = MessageUtility.getUtility().getMessage(vc, IEJBValidatorMessageConstants.CHKJ2814, IEJBValidationContext.WARNING, element, this); |
| vc.addMessage(message); |
| continue; |
| } |
| |
| if (element.getName() != null) { |
| // Do not attempt to access the methods on the home or remote interface if there' |
| // been a problem locating or reflecting those types |
| boolean reflected = true; |
| try { |
| ValidationRuleUtility.isValidType(bean.getHomeInterface()); |
| } |
| catch (InvalidInputException e) { |
| reflected = false; |
| String className = (e.getJavaClass() == null) ? IEJBValidatorConstants.NULL_HOME : e.getJavaClass().getQualifiedName(); |
| String[] msgParm = { className }; |
| IMessage message = MessageUtility.getUtility().getMessage(vc, IEJBValidatorMessageConstants.CHKJ2850, IEJBValidationContext.WARNING, bean, msgParm, this); |
| vc.addMessage(message); |
| } |
| try { |
| ValidationRuleUtility.isValidType(bean.getRemoteInterface()); |
| } |
| catch (InvalidInputException e) { |
| reflected = false; |
| String className = (e.getJavaClass() == null) ? IEJBValidatorConstants.NULL_REMOTE : e.getJavaClass().getQualifiedName(); |
| String[] msgParm = { className }; |
| IMessage message = MessageUtility.getUtility().getMessage(vc, IEJBValidatorMessageConstants.CHKJ2850, IEJBValidationContext.WARNING, bean, msgParm, this); |
| vc.addMessage(message); |
| } |
| |
| if(reflected) { |
| // The "element.getMethods()" has a null pointer exception when it attempts to retrieve the methods from the home/remote interface, |
| // if either of the interfaces don't exist. |
| String name = element.getName(); |
| |
| Method[] methods = element.getMethods(); // get all methods which will be retrieved for the given method-permission |
| boolean hasMethods = ((methods != null) && (methods.length > 0)); |
| |
| if (!hasMethods) { |
| // warning |
| IMessage message = MessageUtility.getUtility().getMessage(vc, IEJBValidatorMessageConstants.CHKJ2843, IEJBValidationContext.WARNING, element, new String[] { bean.getName()}, this); |
| vc.addMessage(message); |
| } |
| else { |
| hasValidMethod = true; // a <method-permission> must have at least one method (15.3.2, p.229) |
| if (name.equals("*")) { //$NON-NLS-1$ |
| List params = element.getMethodParams(); |
| if ((params != null) && (params.size() > 0)) { |
| // warning |
| IMessage message = MessageUtility.getUtility().getMessage(vc, IEJBValidatorMessageConstants.CHKJ2842, IEJBValidationContext.WARNING, element, this); |
| vc.addMessage(message); |
| } |
| } |
| } |
| } |
| } |
| else { |
| // error |
| IMessage message = MessageUtility.getUtility().getMessage(vc, IEJBValidatorMessageConstants.CHKJ2844, IEJBValidationContext.WARNING, element, this); |
| vc.addMessage(message); |
| } |
| } |
| |
| return hasValidMethod; |
| } |
| |
| /** |
| * Need to build up a list of duplicate EJB names, but the validation message |
| * needs to be registered against the duplicate EnterpriseBean instance. |
| * (Without the instance, we cannot get line numbers.) |
| * |
| * This class wrappers the EnterpriseBean 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 EjbNameWrapper { |
| private EnterpriseBean _bean = null; |
| |
| public EjbNameWrapper(EnterpriseBean bean) { |
| _bean = bean; |
| } |
| |
| public boolean equals(Object o) { |
| if (o instanceof EjbNameWrapper) { |
| EjbNameWrapper other = (EjbNameWrapper)o; |
| if((_bean.getName() == null) && (other.getBean().getName() == null)) { |
| return true; |
| } |
| else if(_bean.getName() == null) { |
| return false; |
| } |
| else if(other.getBean().getName() == null) { |
| return false; |
| } |
| return _bean.getName().equals(other.getBean().getName()); |
| } |
| return false; |
| } |
| |
| public int hashCode() { |
| if((getBean() != null) && (getBean().getName() != null)) { |
| return getBean().getName().hashCode(); |
| } |
| return super.hashCode(); |
| } |
| |
| public EnterpriseBean getBean() { |
| return _bean; |
| } |
| } |
| } |