/*
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 1999 Bull S.A.
 * Contact: jonas-team@objectweb.org
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 * USA
 *
 * Initial developer(s): ____________________________________.
 * Contributor(s): Lutris Technologies Inc http://www.lutris.com
 *                 Jeff Mesnil
 *
 * --------------------------------------------------------------------------
 * $Id$
 * --------------------------------------------------------------------------
 * several changes 13.3.00
 * add security implementation mesniljf 17.07.00
 */


package org.objectweb.jonas_ejb.deployment.api;

import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.Vector;
import org.objectweb.jonas_ejb.deployment.xml.*;

/**
 * Base class for bean descriptors
 * @autor Helene Joanin, Christophe Ney
*/
public abstract class BeanDesc {

    protected final static int BEAN_TRANSACTION_TYPE = 1;
    protected final static int CONTAINER_TRANSACTION_TYPE = 2;
    protected final static String[] TRANS = {
	null, 
	"BEAN_TRANSACTION_TYPE", 
	"CONTAINER_TRANSACTION_TYPE"
    };

    private static final String ejb10PropertiesPrefix = "ejb10-properties/";

    protected String displayName = null;
    protected String ejbName = null;
    protected String jndiName = null;
    protected Class home = null;
    protected Class remote = null;
    protected Class localhome = null;
    protected Class local = null;
    protected Class ejbClass = null;
    protected Vector envEntryDesc = new Vector();
    protected Properties ejb10EnvProps = new Properties();
    protected Vector resourceEnvRefDesc = new Vector();
    protected Vector resourceRefDesc = new Vector();
    protected Vector ejbRefDesc = new Vector();
    protected Vector ejbLocalRefDesc = new Vector();

    // Hashtable for methods
    protected Hashtable methodDesc = new Hashtable();
    protected Hashtable securityRoleRef = new Hashtable();

    /**
     * Package protected constructor used by API
     * Note that jndiName, home, remote is null in case of
     * message driven bean.
     */
    BeanDesc(ClassLoader classLoader, DisplayName displayname, EjbName ejbname,
             JndiName jndiname, Home home, Remote remote, LocalHome localhome, Local local, EjbClass ejbClass,
             List envEntryList, List resourceRefList, List jonasResourceList,
             List resourceEnvRefList, List jonasResourceEnvList,
             List ejbRefList, List jonasEjbRefList, List ejbLocalRefList, List securityRoleRefList,
             AssemblyDescriptor asd)
	throws DeploymentDescException {

        // names
        displayName = (displayname != null) ? displayname.getValue() : null;
        ejbName = (ejbname != null) ? ejbname.getValue() : null;

	// If no value given specifically, we use ejbName as JNDI name.
        jndiName = (jndiname != null) ? jndiname.getValue() : ejbName;

        // classes
        if (home != null) {
            try {
                this.home = classLoader.loadClass(home.getValue());
            } catch(ClassNotFoundException e) {
                throw new DeploymentDescException("Home class not found for bean "+ejbName,e);
            }
        }

        if (remote != null) {
            try {
                this.remote = classLoader.loadClass(remote.getValue());
            } catch(ClassNotFoundException e) {
                throw new DeploymentDescException("Remote class not found for bean "+ejbName,e);
            }
        }

        if (localhome != null) {
            try {
                this.localhome = classLoader.loadClass(localhome.getValue());
            } catch(ClassNotFoundException e) {
                throw new DeploymentDescException("LocalHome class not found for bean "+ejbName,e);
            }
        }

        if (local != null) {
            try {
                this.local = classLoader.loadClass(local.getValue());
            } catch(ClassNotFoundException e) {
                throw new DeploymentDescException("Local class not found for bean "+ejbName,e);
            }
        }

        try {
            this.ejbClass = classLoader.loadClass(ejbClass.getValue());
        } catch(ClassNotFoundException e) {
            throw new DeploymentDescException("Ejb class not found for bean "+ejbName,e);
        }

        // env-entries and ejb10 environment properties
        for (Iterator i = envEntryList.iterator(); i.hasNext(); ) {
            envEntryDesc.addElement(new EnvEntryDesc((EnvEntry)i.next()));
        }
	for (Enumeration e = envEntryDesc.elements(); e.hasMoreElements(); ) {
            EnvEntryDesc ed = ((EnvEntryDesc)e.nextElement());
            if ( ed.getName().startsWith(ejb10PropertiesPrefix) ) {
                String newName = ed.getName().substring(ejb10PropertiesPrefix.length());
                String value = new String();
                if (ed.hasValue()) {
                    value = ed.getValue().toString();
                }
                ejb10EnvProps.put(newName, value);
            }
        }

	// resources
        Hashtable resource = new Hashtable();
        for (Iterator i = jonasResourceList.iterator(); i.hasNext(); ) {
	    JonasResource jonasResource=((JonasResource)i.next());
	    String rName = jonasResource.getResRefName().getValue();
	    boolean findResRef = false;
	    for (Iterator j=resourceRefList.iterator(); j.hasNext() && !findResRef;) {
                if (rName.equals(((ResourceRef)j.next()).getResRefName().getValue())) {
                    findResRef = true;
                }
	    }
            if (!findResRef) {
                throw new DeploymentDescException("resource-ref missing for jonas-resource "+rName);
            }
            resource.put(rName,jonasResource);
        }
        for (Iterator i = resourceRefList.iterator(); i.hasNext();) {
            ResourceRef resourceRef = ((ResourceRef)i.next());
            String rName = resourceRef.getResRefName().getValue();
            if (!resource.containsKey(rName))
                throw new DeploymentDescException("jonas-resource missing for res-ref-name "+rName);
            resourceRefDesc.addElement(new ResourceRefDesc(classLoader,resourceRef,(JonasResource)resource.get(rName)));
        }

        // resources-env
        Hashtable resourceEnv = new Hashtable();
        for (Iterator i = jonasResourceEnvList.iterator(); i.hasNext();) {
            JonasResourceEnv jonasResourceEnv = (JonasResourceEnv)i.next();
            String rName = jonasResourceEnv.getResourceEnvRefName().getValue();
            boolean findResRef = false;
            for (Iterator j=resourceEnvRefList.iterator(); j.hasNext() && !findResRef;) {
                ResourceEnvRef resourceEnvRef = (ResourceEnvRef)j.next();
                if (rName.equals(resourceEnvRef.getResourceEnvRefName().getValue())) {
                    findResRef = true;
                }
            }
            if (!findResRef) {
                throw new DeploymentDescException("resource-env-ref missing for jonas-resource-env "+rName);
            }
            resourceEnv.put(rName,jonasResourceEnv);
        }
        for (Iterator i = resourceEnvRefList.iterator(); i.hasNext();) {
            ResourceEnvRef resourceEnvRef = (ResourceEnvRef)i.next();
            String rName = resourceEnvRef.getResourceEnvRefName().getValue();
            if (!resourceEnv.containsKey(rName))
                throw new DeploymentDescException("jonas-resource-env missing for resource-env-ref-name "+rName);
            resourceEnvRefDesc.addElement(new ResourceEnvRefDesc(classLoader, resourceEnvRef, (JonasResourceEnv)resourceEnv.get(rName)));
        }

        // ejb-ref
        Hashtable ejbRef = new Hashtable();
        for (Iterator i = jonasEjbRefList.iterator(); i.hasNext();) {
            JonasEjbRef jonasEjbRef = (JonasEjbRef)i.next();
            String brName = jonasEjbRef.getEjbRefName().getValue();
            boolean findBRef = false;
            for (Iterator j=ejbRefList.iterator(); j.hasNext() && !findBRef;) {
                EjbRef eRef = (EjbRef)j.next();
                if (brName.equals(eRef.getEjbRefName().getValue())) {
                    findBRef = true;
                }
            }
            if (!findBRef) {
                throw new DeploymentDescException("ejb-ref missing for jonas-ejb-ref "+brName);
            }
            ejbRef.put(brName, jonasEjbRef);
        }
        for (Iterator i = ejbRefList.iterator(); i.hasNext();) {
            EjbRef eRef = (EjbRef) i.next();
            String brName = eRef.getEjbRefName().getValue();
	    JonasEjbRef jonasEjbRef = (JonasEjbRef)ejbRef.get(brName);
            if (jonasEjbRef == null) {
		// The ejb-link must be specified when there is no jonas-ejb-ref
		if ((eRef.getEjbLink() == null) ||
		    (eRef.getEjbLink().getValue().indexOf(".jar#") > 0)) {
		    // Ignore the ejb-link syntax "product.jar#ProductEJB"
		    throw new DeploymentDescException("jonas-ejb-ref missing for ejb-ref-name "+brName);
		}
            }
	    ejbRefDesc.addElement(new EjbRefDesc(eRef, jonasEjbRef));
        }

	// ejb-local-ref
	Hashtable ejbLocalRef = new Hashtable();
        for (Iterator i = ejbLocalRefList.iterator(); i.hasNext();) {
	     EjbLocalRef elr = (EjbLocalRef) i.next();
	     EjbLocalRefDesc elrd = new EjbLocalRefDesc(elr);
	     ejbLocalRefDesc.addElement(elrd);
        }

        // populate hashtable with all methods
        try {
            java.lang.reflect.Method [] m;
            if ((this.home != null) && (this.remote != null)) {
                // session bean or entity bean with remote interface
                m = this.home.getMethods();
                for (int i = 0; i < m.length; i++) {
                    if (!m[i].getDeclaringClass().equals(javax.ejb.EJBHome.class) ||
                        m[i].getName().equals("remove")) {
                        methodDesc.put(m[i], new MethodDesc());
                    }
                }
                m = this.remote.getMethods();
                for (int i = 0; i < m.length; i++) {
                    if (!m[i].getDeclaringClass().equals(javax.ejb.EJBObject.class) ||
                        m[i].getName().equals("remove")) {
                        methodDesc.put(m[i], new MethodDesc());
                    }
                }
            }
            if ((this.localhome != null) && (this.local != null)) {
                // session bean or entity bean with local interface
                m = this.localhome.getMethods();
                for (int i = 0; i < m.length; i++) {
                    if (!m[i].getDeclaringClass().equals(javax.ejb.EJBLocalHome.class) ||
                        m[i].getName().equals("remove")) {
                        methodDesc.put(m[i], new MethodDesc());
                    }
                }
                m = this.local.getMethods();
                for (int i = 0; i < m.length; i++) {
                    if (!m[i].getDeclaringClass().equals(javax.ejb.EJBLocalObject.class) ||
                        m[i].getName().equals("remove")) {
                        methodDesc.put(m[i],new MethodDesc());
                    }
                }
            }
	    if (this.home == null && this.localhome == null) {
                // message driven bean
                m = javax.jms.MessageListener.class.getMethods();
                for (int i = 0; i < m.length; i++) {
                    if (m[i].getName().equals("onMessage")) {
                        methodDesc.put(m[i], new MethodDesc());
                    }
                }
            }
        } catch (SecurityException e){
            throw new DeploymentDescException("Cannot use java reflection on "+ejbName);
        }

        // populate hashtable with all security role references
        // for each security-role-ref of the bean
        if (securityRoleRefList != null) {
	    for (Iterator i = securityRoleRefList.iterator(); i.hasNext();) {
		SecurityRoleRef sRoleRef = (SecurityRoleRef)i.next();
		// test if the assembly-descriptor element exists
		if (asd == null) {
		    throw new DeploymentDescException("No assembly-descriptor element (and security-role elements) whereas security-role-ref element(s) are defined");
		}
		else {
		    // test if the assembly-descriptor element contains security-role elements
		    if (asd.getSecurityRoleList().isEmpty()) {
			throw new DeploymentDescException("No security-role elements defined in the assembly-descriptor element  whereas security-role-ref element(s) are defined");
		    }
		}
		// test if the role-link element of the security-role-ref element exists
		if (sRoleRef.getRoleLink() == null) {
		    throw new DeploymentDescException("No role-link element in a security-role-ref element with role-name element : "+ sRoleRef.getRoleName());
		}
		String roleLink = sRoleRef.getRoleLink().getValue();
		// correspond to role-name element in security-role-ref element
		String roleRefName = sRoleRef.getRoleName().getValue();
		// to know if there are corresponding roleLink and roleRefName
		boolean correspondingRoles = false;
		for (Iterator j = asd.getSecurityRoleList().iterator(); j.hasNext();) {
		    SecurityRole securityRole=(SecurityRole)j.next();
		    // role name of a security-role element defined in the assembly descriptor
		    String roleName =  securityRole.getRoleName().getValue();
		    if (roleName.equals(roleLink)) {
			securityRoleRef.put (roleRefName, roleLink);
			correspondingRoles = true;
		    }
		}
		//if there are no matching roleLink and roleName
		if (!correspondingRoles) {
		    throw new DeploymentDescException("No corresponding role-name in a security-role element for role-link : " + roleLink);
		}
	    }
        }

	// check if there are corresponding role-name element in security-role
	// and method-permission element of the Assembly Descriptor
        if (asd != null) {
            verifyRoleName(asd);
            // set  method descriptor values for method permissions
            for (Iterator i =  asd.getMethodPermissionList().iterator(); i.hasNext();) {
                MethodPermission methodPermission = (MethodPermission)i.next();
                for (Iterator j = methodPermission.getMethodList().iterator(); j.hasNext();) {
                    Method m = ((Method)j.next());
                    // check method applies to current bean
                    if (!m.getEjbName().getValue().equals(ejbName))
                        continue;
                    // selection of interface home/remote
                    Class pClass = null;
                    if (m.getMethodIntf() != null) {
                        if (m.getMethodIntf().getValue().equals("Home"))
                            pClass = javax.ejb.EJBHome.class;
                        else if (m.getMethodIntf().getValue().equals("Remote"))
                            pClass = javax.ejb.EJBObject.class;
			else if (m.getMethodIntf().getValue().equals("LocalHome"))
                            pClass = javax.ejb.EJBLocalHome.class;
                        else if (m.getMethodIntf().getValue().equals("Local"))
                            pClass = javax.ejb.EJBLocalObject.class;
                        else
                            throw new DeploymentDescException(m.getMethodIntf().getValue()+" is invalid value for method-intf on bean "+ejbName);
                    }
                    // loop on methods in the hashtable
                    Enumeration e = methodDesc.keys();
                    while (e.hasMoreElements()) {
                        java.lang.reflect.Method meth = (java.lang.reflect.Method)e.nextElement();
                        // status of method name pattern matching
                        int matchStatus = MethodDesc.matchPattern(meth, pClass, m.getMethodName().getValue(), m.getMethodParams());
                        MethodDesc md = (MethodDesc) methodDesc.get(meth);

                        for (Iterator k= methodPermission.getRoleNameList().iterator(); k.hasNext();) {
                            String roleName = ((RoleName)k.next()).getValue();
                            md.addRoleName(roleName, matchStatus);
                        }
                    }
                }
            }
        }

        // set method descriptor values for container transactions
        if (asd != null) {
	    // Loop on ContainerTransaction list
	    Iterator i = asd.getContainerTransactionList().iterator();
            while (i.hasNext()) {
                ContainerTransaction cotr = (ContainerTransaction) i.next();
		// Loop on Method list
		Iterator j = cotr.getMethodList().iterator();
                while (j.hasNext()) {
                    Method m = (Method) j.next();

                    // check method applies to current bean
                    if (!m.getEjbName().getValue().equals(ejbName))
                        continue;

                    // selection of interface home/remote
                    Class pClass = null;
                    if (m.getMethodIntf() != null) {
			String mintf = m.getMethodIntf().getValue();
                        if (mintf.equals("Home"))
                            pClass = javax.ejb.EJBHome.class;
                        else if (mintf.equals("Remote"))
                            pClass = javax.ejb.EJBObject.class;
			else if (mintf.equals("LocalHome"))
                            pClass = javax.ejb.EJBLocalHome.class;
                        else if (mintf.equals("Local"))
                            pClass = javax.ejb.EJBLocalObject.class;
                        else
                            throw new DeploymentDescException(mintf+" is invalid value for method-intf on bean "+ejbName);
                    }

                    // loop on methods in the hashtable
                    Enumeration e = methodDesc.keys();
                    boolean found = false;
                    while (e.hasMoreElements()) {
                        java.lang.reflect.Method meth = (java.lang.reflect.Method) e.nextElement();
                        // status of method name pattern matching
                        int matchStatus = MethodDesc.matchPattern(meth, pClass, m.getMethodName().getValue(), m.getMethodParams());
                        if (matchStatus != MethodDesc.APPLY_TO_NOTHING) {
                            found = true;
                        }
                        MethodDesc md = (MethodDesc)methodDesc.get(meth);
                        // set if proper level of assignation
                        String transAttribute = null;
                        if (cotr.getTransAttribute() != null)
                            transAttribute  = cotr.getTransAttribute().getValue();
                        md.overwriteTxAttribute(transAttribute,matchStatus);
                    }
                    if (!found) {
                        // The method defined via the <method> element is not a declared method
                        throw new DeploymentDescException("Invalid container-transaction: method '"
                                                          +MethodDesc.methodElementToString(m)
                                                          +"' not declared in bean "+ejbName);
                    }
                }
            }
        }
    }


    /**
     * Check that the bean descriptor is valid
     * @exception DeploymentDescException thrown for non-valid bean
     */
    public void check() throws DeploymentDescException {
        // check method descriptors
        Enumeration e = methodDesc.keys();
        while (e.hasMoreElements()) {
            java.lang.reflect.Method m = (java.lang.reflect.Method)e.nextElement();
            checkTxAttribute(m);
        }
    }

    /**
     * check that trans-attribute is valid for bean
     */
    protected abstract void checkTxAttribute(java.lang.reflect.Method method) throws DeploymentDescException;

    /**
     * check that there are always corresponding role-name element
     * in security-role and method-permission elements
     */
    protected void verifyRoleName (AssemblyDescriptor asd) throws DeploymentDescException {
        boolean verify;
        List methodPermission = asd.getMethodPermissionList();
        if (methodPermission != null) {
            for (Iterator i = methodPermission.iterator(); i.hasNext();) {
                MethodPermission mPermission = (MethodPermission)i.next();
                for (Iterator j = mPermission.getRoleNameList().iterator(); j.hasNext();) {
                    verify = false;
                    String mpRoleName = ((RoleName)j.next()).getValue();
                    for (Iterator k = asd.getSecurityRoleList().iterator(); k.hasNext(); ) {
                        String srRoleName = ((SecurityRole)k.next()).getRoleName().getValue();
                        if (mpRoleName.equals(srRoleName)) {
                            verify = true;
                        }
                    }
                    if (!verify) {
                        throw new DeploymentDescException ("a method-permission element defined a role-name element \""+mpRoleName+"\" which doesn't correspond to any security-role element of the Deployment Descriptor");
                    }
                }
            }
        }
    }

    /**
     * Get the displayName of the bean.
     * Used by Server
     * @return null if not set
     */
    public String getDisplayName(){
        return displayName;
    }

    /**
     * Get the enterprise bean's name.
     * @return Name of the bean
     */
    public String getEjbName(){
        return ejbName;
    }

    /**
     * Get the name to associate with the enterprise Bean in the JNDI name space.
     * Invoking this method is disallowed for message driven bean.
     * (This information is JOnAS specific). Used by Server
     * @return Jndi name of the bean
     */
    public String getJndiName() {
        if (jndiName == null) {
            throw new Error("Disallowed invocation of BeanDesc.getJndiName()");
        }
        return jndiName;
    }

    /**
     * Get the name to associate with the enterprise Bean in the JNDI name space
     * for local access (inside the same EJBServer)
     * @return Jndi name of the bean
     */
    public String getJndiLocalName() {
	if (jndiName == null) {
            throw new Error("Disallowed invocation of BeanDesc.getJndiLocalName()");
        }
	return jndiName+"_L";
    }

    /**
     * Get bean's home interface.
     * Invoking this method is disallowed for message driven bean.
     * Used by GenIC and Server
     * @return Class for the home interface or null
     */
    public Class getHomeClass() {
        return home;
    }

    /**
     * Get bean's remote interface.
     * Invoking this method is disallowed for message driven bean.
     * Used by GenIC and Server
     * @return Class for the remote interface or null
     */
    public Class getRemoteClass() {
        return remote;
    }

    /**
     * Get bean's local home interface.
     * Invoking this method is disallowed for message driven bean.
     * Used by GenIC and Server
     * @return Class for the home interface or null
     */
    public Class getLocalHomeClass() {
        return localhome;
    }

    /**
     * Get bean's local interface.
     * Invoking this method is disallowed for message driven bean.
     * Used by GenIC and Server
     * @return Class for the Local interface or null
     */
    public Class getLocalClass() {
        return local;
    }

    /**
     * Get bean's class.
     * Used by GenIC and Server
     * @return Class for the bean
     */
    public Class getEjbClass() {
        return ejbClass;
    }

    /**
     * Get bean's environment entries.
     * Used by Server
     * @return array of resource reference descriptors (may be empty)
     */
    public EnvEntryDesc[] getEnvEntryDesc() {
        EnvEntryDesc ret[] = new EnvEntryDesc[envEntryDesc.size()];
        envEntryDesc.copyInto(ret);
        return ret;
    }

    /**
     * Get bean's EJB 1.0 environment properties
     */
    public Properties getEjb10Environment() {
	Properties ret = new Properties(ejb10EnvProps);
	return ret;
    }

    /**
     * Get bean's resource environment references.
     * Used by Server
     * @return array of resource environment reference descriptors (may be empty)
     */
    public ResourceEnvRefDesc[] getResourceEnvRefDesc(){
        ResourceEnvRefDesc ret[] = new ResourceEnvRefDesc[resourceEnvRefDesc.size()];
        resourceEnvRefDesc.copyInto(ret);
        return ret;
    }

    /**
     * Get bean's resource manager connection factory references.
     * Used by Server
     * @return array of resource reference descriptors (may be empty)
     */
    public ResourceRefDesc[] getResourceRefDesc(){
        ResourceRefDesc ret[] = new ResourceRefDesc[resourceRefDesc.size()];
        resourceRefDesc.copyInto(ret);
        return ret;
    }

    /**
     * Get bean's ejb references.
     * Used by Server
     * @return array of ejb reference descriptors (may be empty)
     */
    public EjbRefDesc[] getEjbRefDesc(){
        EjbRefDesc ret[] = new EjbRefDesc[ejbRefDesc.size()];
        ejbRefDesc.copyInto(ret);
        return ret;
    }

    /**
     * Get bean's ejb local references.
     * Used by Server
     * @return array of ejb local reference descriptors (may be empty)
     */
    public EjbLocalRefDesc[] getEjbLocalRefDesc(){
        EjbLocalRefDesc ret[] = new EjbLocalRefDesc[ejbLocalRefDesc.size()];
        ejbLocalRefDesc.copyInto(ret);
        return ret;
    }

    /**
     * Get descriptor attached to a given method.
     * Used by GenIC
     * @param method Method from the Home/Remote/MessageListener interface
     * @return The method descriptor (never returns null)
     */
    public MethodDesc getMethodDesc(java.lang.reflect.Method method) {
        if (!methodDesc.containsKey(method))
            throw new Error(method.getName()+" is not a method of home/remote interfaces for bean "+getEjbName());
        return (MethodDesc)methodDesc.get(method);
    }

    public Hashtable getMethodDescs() {
        return methodDesc;
    }

    /**
     * Get the role-link value corresponding to the role-name value of a security-role-ref element
     *
     * @param roleName String corresponding to the role-name value of a security-role-ref element
     * @return String corresponding to the role-link value
     */
    public String getRoleLink (String roleName) {
        String roleLink = (String)securityRoleRef.get(roleName);
        return roleLink;
    }

    /**
     * Get all the role names defined in the security-role-ref elements of the bean
     *
     * @param roleName String corresponding to the role-name value of a security-role-ref element
     * @return String corresponding to the role-link value
     */
    public String[] getSecurityRoleNames () {
        Enumeration e = securityRoleRef.keys();
        String[] roleNames = new String [securityRoleRef.size()];
        int i = 0;
        while (e.hasMoreElements()) {
            roleNames[i] = (String) e.nextElement();
            i ++;
        }
        return roleNames;
    }

    /**
     * String representation of the object for test purpose
     * @return String representation of this object
     */
    public String toString() {
        StringBuffer ret = new StringBuffer();
        ret.append("\ngetDisplayName()="+getDisplayName());
        ret.append("\ngetEjbName()="+getEjbName());
        if (jndiName != null) {
            ret.append("\ngetJndiName()="+getJndiName());
        }
        if (home != null) {
            ret.append("\ngetHomeClass()="+getHomeClass().toString());
        }
        if (remote != null) {
            ret.append("\ngetRemoteClass()="+getRemoteClass().toString());
        }
        if (localhome != null) {
            ret.append("\ngetLocalHomeClass()="+getLocalHomeClass().toString());
        }
        if (local != null) {
            ret.append("\ngetLocalClass()="+getLocalClass().toString());
        }
        ret.append("\ngetEjbClass()="+getEjbClass().toString());
        EnvEntryDesc[] envE = getEnvEntryDesc();
        for (int i = 0; i < envE.length; i++) {
            ret.append("\ngetEnvEntryDesc("+i+")="+envE[i].toString());
        }
        ResourceEnvRefDesc[] resEnvR = getResourceEnvRefDesc();
        for (int i = 0; i < resEnvR.length; i++) {
            ret.append("\ngetResourceEnvRefDesc("+i+")="+resEnvR[i].toString());
        }
        ResourceRefDesc[] resR = getResourceRefDesc();
        for (int i = 0; i < resR.length; i++) {
            ret.append("\ngetResourceRefDesc("+i+")="+resR[i].toString());
        }
        EjbRefDesc[] ejbR = getEjbRefDesc();
        for (int i = 0; i < ejbR.length; i++) {
            ret.append("\ngetEjbRefDesc("+i+")="+ejbR[i].toString());
        }
        EjbLocalRefDesc[] ejbLR = getEjbLocalRefDesc();
        for (int i = 0; i < ejbLR.length; i++) {
            ret.append("\ngetEjbLocalRefDesc("+i+")="+ejbLR[i].toString());
        }
        Enumeration e = methodDesc.keys();
        while (e.hasMoreElements()) {
            java.lang.reflect.Method m = (java.lang.reflect.Method)e.nextElement();
            MethodDesc md = getMethodDesc(m);
            ret.append("\ngetMethodDesc("+m.toString()+")="+md.getClass().getName());
            ret.append(md.toString());
        }
        e = securityRoleRef.keys();
        while (e.hasMoreElements()) {
            String roleName = (String)e.nextElement();
            ret.append("\ngetRoleLink("+ roleName +") = "+ getRoleLink(roleName));
        }
        return ret.toString();
    }
}

