/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 1999-2006 Bull S.A.
 * Contact: jonas-team@ow2.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
 *
 * --------------------------------------------------------------------------
 * $Id: BeanDesc.java 15579 2008-10-17 12:28:11Z eyindanga $
 * --------------------------------------------------------------------------
 */

package org.ow2.jonas.deployment.ejb;

import java.lang.reflect.Modifier;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;

import org.objectweb.util.monolog.api.BasicLevel;
import org.omg.CSI.ITTAbsent;
import org.omg.CSI.ITTAnonymous;
import org.omg.CSI.ITTDistinguishedName;
import org.omg.CSI.ITTPrincipalName;
import org.omg.CSI.ITTX509CertChain;
import org.omg.CSIIOP.Confidentiality;
import org.omg.CSIIOP.EstablishTrustInClient;
import org.omg.CSIIOP.EstablishTrustInTarget;
import org.omg.CSIIOP.IdentityAssertion;
import org.omg.CSIIOP.Integrity;
import org.ow2.carol.util.csiv2.SasComponent;
import org.ow2.carol.util.csiv2.struct.AsStruct;
import org.ow2.carol.util.csiv2.struct.SasStruct;
import org.ow2.carol.util.csiv2.struct.TransportStruct;
import org.ow2.jonas.deployment.api.IEJBLocalRefDesc;
import org.ow2.jonas.deployment.api.IEJBRefDesc;
import org.ow2.jonas.deployment.api.IEnvEntryDesc;
import org.ow2.jonas.deployment.api.IMessageDestinationRefDesc;
import org.ow2.jonas.deployment.api.IResourceEnvRefDesc;
import org.ow2.jonas.deployment.api.IResourceRefDesc;
import org.ow2.jonas.deployment.api.IServiceRefDesc;
import org.ow2.jonas.deployment.common.DeploymentDescException;
import org.ow2.jonas.deployment.common.JndiEnvRefsGroupDesc;
import org.ow2.jonas.deployment.common.SecurityRoleRefDesc;
import org.ow2.jonas.deployment.common.lib.JavaType;
import org.ow2.jonas.deployment.common.xml.JLinkedList;
import org.ow2.jonas.deployment.common.xml.RunAs;
import org.ow2.jonas.deployment.common.xml.SecurityRole;
import org.ow2.jonas.deployment.common.xml.SecurityRoleRef;
import org.ow2.jonas.deployment.ejb.xml.AsContextMapping;
import org.ow2.jonas.deployment.ejb.xml.AssemblyDescriptor;
import org.ow2.jonas.deployment.ejb.xml.CommonEjb;
import org.ow2.jonas.deployment.ejb.xml.ContainerTransaction;
import org.ow2.jonas.deployment.ejb.xml.IorSecurityConfigMapping;
import org.ow2.jonas.deployment.ejb.xml.JonasCommonEjb;
import org.ow2.jonas.deployment.ejb.xml.Method;
import org.ow2.jonas.deployment.ejb.xml.MethodPermission;
import org.ow2.jonas.deployment.ejb.xml.SasContextMapping;
import org.ow2.jonas.deployment.ejb.xml.TransportConfigMapping;
import org.ow2.jonas.lib.util.BeanNaming;

/**
 * Class to hold meta-information related to any enterprise-beans
 *
 * @author Christophe Ney [cney@batisseurs.com] : Initial developer
 * @author Helene Joanin
 * @author Jeff Mesnil
 * @author Philippe Coq
 * @author Florent Benoit & Ludovic Bert : ejb_link
 */
public abstract class BeanDesc extends JndiEnvRefsGroupDesc {

    /**
     * Bean transaction type
     */
    protected static final int BEAN_TRANSACTION_TYPE = 1;

    /**
     * Container transaction type
     */
    protected static final int CONTAINER_TRANSACTION_TYPE = 2;

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

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

    /**
     * When no jndi-name specified, jndi name is set to Ejb-Name + "Home"
     */
    private static final String REMOTEDEFAULTSUFFIX = "Home";

    /**
     * When no local-jndi-name specified, local jndi name is set to jndi-name +
     * "_L"
     */
    private static final String LOCALDEFAULTSUFFIX = "_L";

    /**
     * Package prefix for generated files
     */
    public static final String GENERATED_PREFIX = "org.ow2.jonas_gen.";

    /**
     * name of the Bean
     */
    protected String ejbName = null;

    /**
     * JNDI name of the Bean
     */
    protected String jndiName = null;

    /**
     * JNDI local name of the Bean
     */
    protected String jndiLocalName = null;

    /**
     * Home Class
     */
    protected Class home = null;

    /**
     * Remote Class
     */
    protected Class remote = null;

    /**
     * LocalHome Class
     */
    protected Class localhome = null;

    /**
     * Local Class
     */
    protected Class local = null;

    /**
     * Bean Class
     */
    protected Class ejbClass = null;

    /**
     * bean identification string
     */
    protected String beanIdentification = null;

    /**
     * EJB 1.0 Environment as Properties
     */
    protected Properties ejb10EnvProps = new Properties();

    /**
     * array of methods meta-info
     */
    private ArrayList methodDesc = new ArrayList();

    /**
     * hash map of the methods
     */
    private HashMap methodDescMap = new HashMap();

    /**
     * List of SecurityRoleRefDesc for JACC
     */
    protected List securityRoleRefDescList = null;

    /**
     * DeploymentDesc parent of this BeanDesc
     */
    protected DeploymentDesc deploymentDesc = null;

    /**
     * JOnAS Remote Wrapper fully qualified classname
     */
    private String fullWrpRemoteName = null;

    /**
     * JOnAS Remote Wrapper Classname
     */
    private String wrpRemoteName = null;

    /**
     * JOnAS Home Wrapper fully qualified classname
     */
    private String fullWrpHomeName = null;

    /**
     * JOnAS Home Wrapper Classname
     */
    private String wrpHomeName = null;

    /**
     * JOnAS Local Wrapper fully qualified classname
     */
    private String fullWrpLocalName = null;

    /**
     * JOnAS Local Wrapper Classname
     */
    private String wrpLocalName = null;

    /**
     * JOnAS LocalHome Wrapper fully qualified classname
     */
    private String fullWrpLocalHomeName = null;

    /**
     * JOnAS LocalHome Wrapper Classname
     */
    private String wrpLocalHomeName = null;

    /**
     * JOnAS Handle Wrapper fully qualified classname
     */
    private String fullWrpHandleName = null;

    /**
     * JOnAS Handle Wrapper Classname
     */
    private String wrpHandleName = null;

    /**
     * Bean fully qualified classname
     */
    protected String fullDerivedBeanName = null;

    /**
     * Bean classname
     */
    protected String derivedBeanName = null;

    /**
     * Run-as role
     */
    private String runAsRole = null;

    /**
     * Run-as principal name
     */
    private String runAsPrincipalName = null;

    /**
     * Minimum Bean Pool size
     */
    protected int poolMin = 0;

    /**
     * Maximum Bean Cache size
     */
    protected int cacheMax = 0;

    /**
     * SasComponent (for CSIv2 over IIOP)
     */
    private SasComponent sasComponent = null;

    protected int timerTxAttribute = MethodDesc.TX_REQUIRES_NEW; // default

    protected String ejbTimeoutSignature;

    /**
     * Cluster - true if the bean has to be replicated
     */
    protected boolean clusterReplicated = false;
    /**
     * The cluster configuration
     */

    private Object cluster;

    /**
     * Constructor to be used by parent node
     *
     * @param classLoader ClassLoader used to load Bean's classes
     * @param ejb XML Element from standard Deployment Descriptor
     * @param jonasEjb XML Element from jonas specific Deployment Descriptor
     * @param asd XML Element for the AssemblyDescriptor
     * @param fileName jar filename
     *
     * @throws DeploymentDescException when BeanDesc cannot be instanciated
     *         (class loading problem, ...)
     */
    public BeanDesc(final ClassLoader classLoader, final CommonEjb ejb, final JonasCommonEjb jonasEjb, final AssemblyDescriptor asd,
            final JLinkedList jMDRList, final String fileName) throws DeploymentDescException {

        super(classLoader, ejb, jonasEjb, fileName);
        securityRoleRefDescList = new LinkedList();
        if (ejb.getEjbName() != null) {
            ejbName = ejb.getEjbName();
        } else {
            ejbName = null;
        }

        // If no value given specifically, we use the optionnal mapped-name in standardDD or ejbName+Home as JNDI name.
        if (jonasEjb.getJndiName() != null) {
            jndiName = jonasEjb.getJndiName();
        } else if (ejb.getMappedName() != null) {
            jndiName = ejb.getMappedName();
        } else {
            jndiName = ejbName + REMOTEDEFAULTSUFFIX;
        }
        // If no value given specifically, we use the optionnal mapped-name in standardDD jndiName+_L as JNDI local
        // name.
        if (jonasEjb.getJndiLocalName() != null) {
            jndiLocalName = jonasEjb.getJndiLocalName();
        } else {
            jndiLocalName = jndiName + LOCALDEFAULTSUFFIX;
        }

        // classes
        // --------------------------------------------------
        if (ejb.getHome() != null) {
            try {
                this.home = classLoader.loadClass(ejb.getHome());
                // check home extends javax.ejb.EJBHome
                if (!javax.ejb.EJBHome.class.isAssignableFrom(this.home)) {
                    throw new DeploymentDescException("Home class '" + ejb.getHome()
                            + "' does not extend javax.ejb.EJBHome");
                }
            } catch (ClassNotFoundException e) {
                throw new DeploymentDescException("Home class not found for bean " + ejbName, e);
            }
        }

        if (ejb.getRemote() != null) {
            try {
                this.remote = classLoader.loadClass(ejb.getRemote());
                // check remote extends javax.ejb.EJBObject
                if (!javax.ejb.EJBObject.class.isAssignableFrom(this.remote)) {
                    throw new DeploymentDescException("Remote class '" + ejb.getRemote()
                            + "' does not extend javax.ejb.EJBObject");
                }
            } catch (ClassNotFoundException e) {
                throw new DeploymentDescException("Remote class not found for bean " + ejbName, e);
            }
        }

        String localhomename = ejb.getLocalHome();
        // Note: Should do this only if bean is implied in a relation.
        if (localhomename == null && this instanceof EntityCmp2Desc) {
            localhomename = "javax.ejb.EJBLocalHome";
        }
        if (localhomename != null) {
            try {
                this.localhome = classLoader.loadClass(localhomename);
                // check localhome extends javax.ejb.EJBLocalHome
                if (!javax.ejb.EJBLocalHome.class.isAssignableFrom(this.localhome)) {
                    throw new DeploymentDescException("LocalHome class '" + localhomename
                            + "' does not extend javax.ejb.EJBLocalHome");
                }
            } catch (ClassNotFoundException e) {
                throw new DeploymentDescException("LocalHome class not found for bean " + ejbName, e);
            }
        }

        String localname = ejb.getLocal();
        // Note: Should do this only if bean is implied in a relation.
        if (localname == null && this instanceof EntityCmp2Desc) {
            localname = "javax.ejb.EJBLocalObject";
        }
        if (localname != null) {
            try {
                this.local = classLoader.loadClass(localname);
                // check local extends javax.ejb.EJBLocalObject
                if (!javax.ejb.EJBLocalObject.class.isAssignableFrom(this.local)) {
                    throw new DeploymentDescException("Local class '" + localname
                            + "' does not extend javax.ejb.EJBLocalObject");
                }
            } catch (ClassNotFoundException e) {
                throw new DeploymentDescException("Local class not found for bean " + ejbName, e);
            }
        }

        // permit to load service-endpoint class
        loadExtraClasses(ejb, classLoader);

        try {
            this.ejbClass = classLoader.loadClass(ejb.getEjbClass());
            // check ejb-class extends javax.ejb.EnterpriseBean
            if (!javax.ejb.EnterpriseBean.class.isAssignableFrom(this.ejbClass)) {
                throw new DeploymentDescException("Ejb class '" + ejb.getEjbClass()
                        + "' does not extend javax.ejb.EnterpriseBean");
            }
        } catch (ClassNotFoundException e) {
            throw new DeploymentDescException("Ejb class not found for bean " + ejbName, e);
        }

        // Set EJB 1.0 Environment properties from env entries
        IEnvEntryDesc[] envt = getEnvEntryDesc();
        for (int i = 0; i < envt.length; i++) {
            if (envt[i].getName().startsWith(ejb10PropertiesPrefix)) {
                String newName = envt[i].getName().substring(ejb10PropertiesPrefix.length());
                String value = new String();
                if (envt[i].hasValue()) {
                    value = envt[i].getValue().toString();
                }
                ejb10EnvProps.put(newName, value);
            }
        }

        // run-as
        if (ejb.getSecurityIdentity() != null) {
            RunAs runAsElem = ejb.getSecurityIdentity().getRunAs();
            if (runAsElem != null) {
                String roleName = runAsElem.getRoleName();
                if (roleName != null) {
                    runAsRole = roleName;
                    boolean runAsRoleFound = false;
                    if (asd != null && asd.getSecurityRoleList() != null) {
                        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 r = securityRole.getRoleName();
                            if (r.equals(runAsRole)) {
                                runAsRoleFound = true;
                            }
                        }
                    }
                    //if there are no matching run-as and security-role
                    if (!runAsRoleFound) {
                        throw new DeploymentDescException("There is no security-role defined for the run-as role: "
                                + runAsRole);
                    }
                }
                // Run-as principal name
                runAsPrincipalName = jonasEjb.getRunAsPrincipalName();
                // if no principal name set in JOnAS DD, set it to run-as role
                if (runAsPrincipalName == null) {
                    runAsPrincipalName = runAsRole;
                }
            }
        }

        // populate array with all methods
        try {
            java.lang.reflect.Method[] m;
            int beginIdx = methodDesc.size();
            int len = 0;
            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")) {
                        addMethodDesc(m[i], this.home);
                        len++;
                        // check RemoteException is thrown
                        checkRemoteException(m[i], true);
                        /*
                         * // arguments and return types must be valid types for
                         * RMI if
                         * (!m[i].getDeclaringClass().equals(javax.ejb.EJBHome.class) &&
                         * !m[i].getName().equals("findByPrimaryKey")) {
                         * checkValidTypesForRmi(m[i]); }
                         */
                    }
                }

                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")) {
                        addMethodDesc(m[i], this.remote);
                        len++;
                        // check RemoteException is thrown
                        checkRemoteException(m[i], true);
                        /*
                         * // arguments and return types must be valid for RMI
                         * if
                         * (!m[i].getDeclaringClass().equals(javax.ejb.EJBObject.class)) {
                         * checkValidTypesForRmi(m[i]); }
                         */
                    }
                }
            }
            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")) {
                        addMethodDesc(m[i], this.localhome);
                        len++;
                        // check RemoteException is NOT thrown
                        checkRemoteException(m[i], false);
                    }
                }
                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")) {
                        addMethodDesc(m[i], this.local);
                        len++;
                        // check RemoteException is NOT thrown
                        checkRemoteException(m[i], false);
                    }
                }
            }
            if (this.home == null && this.localhome == null) {

                if (ejb.getMessagingType() != null) {
                    // message driven bean & endpoints
                    String msgType = ejb.getMessagingType();
                    try {
                        m = classLoader.loadClass(msgType).getMethods();
                        for (int i = 0; i < m.length; i++) {
                            addMethodDesc(m[i], m[i].getDeclaringClass());
                            len++;
                        }
                    } catch (Exception ex) {
                        throw new DeploymentDescException("Cannot load messaging type class (" + msgType + ") for "
                                + ejbName, ex);
                    }
                }
                // (web)service-endpoints may have no home or local-home too !!
            }

            if (javax.ejb.EntityBean.class.isAssignableFrom(this.ejbClass)) {
                // ejbSelect methods
                m = this.ejbClass.getMethods();
                for (int i = 0; i < m.length; i++) {
                    if (m[i].getName().startsWith("ejbSelect") && Modifier.isAbstract(m[i].getModifiers())) {
                        addMethodDesc(m[i], this.ejbClass);
                        len++;
                    }
                }
            }

            if (javax.ejb.TimedObject.class.isAssignableFrom(this.ejbClass)) {
                try {
                    java.lang.reflect.Method timeout = this.ejbClass.getMethod("ejbTimeout",
                            new Class[]{javax.ejb.Timer.class});
                    addMethodDesc(timeout, this.ejbClass);
                    len++;
                } catch (NoSuchMethodException e) {
                    throw new DeploymentDescException("ejbTimeout not implemented in " + ejbName);
                }
            }

            len = addEJBMethodDesc(len);
            orderMethodDesc(methodDesc, beginIdx, len);
        } catch (SecurityException e) {
            throw new DeploymentDescException("Cannot use java reflection on " + ejbName, e);
        }

        // populate HashMap with all security role references
        // for each security-role-ref of the bean
        if (ejb.getSecurityRoleRefList() != null) {
            for (Iterator i = ejb.getSecurityRoleRefList().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();
                // correspond to role-name element in security-role-ref element
                String roleRefName = sRoleRef.getRoleName();
                // 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();
                    if (roleName.equals(roleLink)) {
                        securityRoleRefDescList.add(new SecurityRoleRefDesc(ejbName, sRoleRef, true));
                        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().equals(ejbName)) {
                        continue;
                    }
                    // selection of interface home/remote
                    Class pClass = null;
                    if (m.getMethodIntf() != null) {
                        pClass = getParentClass(m.getMethodIntf());
                    }
                    for (int k = 0; k < methodDesc.size(); k++) {
                        MethodDesc md = (MethodDesc) methodDesc.get(k);
                        int matchStatus = md.matchPattern(pClass, m.getMethodName(), m.getMethodParams());
                        for (Iterator l = methodPermission.getRoleNameList().iterator(); l.hasNext();) {
                            String roleName = (String) l.next();
                            // Add only if it greater than APPLY_TO_NOTHING
                            if (matchStatus > MethodDesc.APPLY_TO_NOTHING) {
                                md.addRoleName(roleName);
                            }
                        }
                    }
                }
            }
        }

        // Set excluded method
        if (asd != null && asd.getExcludeList() != null) {
            // For each excluded method, find a methodDesc corresponding to this excluded method
            for (Iterator i = asd.getExcludeList().getMethodList().iterator(); i.hasNext();) {
                Method m = (Method) i.next();
                // check method applies to current bean
                if (!m.getEjbName().equals(ejbName)) {
                    continue;
                }
                // selection of interface home/remote
                Class pClass = null;
                if (m.getMethodIntf() != null) {
                    pClass = getParentClass(m.getMethodIntf());
                }
                // Find methodDesc with matching pattern of excluded method
                for (int k = 0; k < methodDesc.size(); k++) {
                    MethodDesc md = (MethodDesc) methodDesc.get(k);
                    int matchStatus = md.matchPattern(pClass, m.getMethodName(), m.getMethodParams());
                    // Add only if it greater than APPLY_TO_NOTHING
                    if (matchStatus > MethodDesc.APPLY_TO_NOTHING) {
                        md.setExcluded(true);
                    }
                }
            }
        }

        // 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().equals(ejbName)) {
                        continue;
                    }

                    // selection of interface home/remote
                    Class pClass = null;
                    if (m.getMethodIntf() != null) {
                        pClass = getParentClass(m.getMethodIntf());
                    }

                    // loop on methods in the array
                    boolean found = false;
                    for (int k = 0; k < methodDesc.size(); k++) {
                        MethodDesc md = (MethodDesc) methodDesc.get(k);
                        int matchStatus = md.matchPattern(pClass, m.getMethodName(), m.getMethodParams());
                        if (matchStatus != MethodDesc.APPLY_TO_NOTHING) {
                            found = true;
                        }
                        // set if proper level of assignation
                        String transAttribute = null;
                        if (cotr.getTransAttribute() != null) {
                            transAttribute = cotr.getTransAttribute();
                        }
                        md.overwriteTxAttribute(transAttribute, matchStatus);
                    }
                    if (!found) {
                        // The method defined via the <method> element is not a
                        // declared method
                        logger.log(BasicLevel.WARN, "Invalid container-transaction: method '"
                                + MethodDesc.methodElementToString(m) + "' not declared in bean " + ejbName);
                    }
                }
            }
        }

        String packageName = "";
        String ejbIdentifier = getIdentifier();

        if (getRemoteClass() != null) {
            packageName = GENERATED_PREFIX + BeanNaming.getPackageName(getRemoteClass().getName());
            wrpRemoteName = new String("JOnAS" + ejbIdentifier + "Remote");
            wrpHandleName = new String("JOnAS" + ejbIdentifier + "Handle");
            fullWrpRemoteName = BeanNaming.getClassName(packageName, wrpRemoteName);
            fullWrpHandleName = BeanNaming.getClassName(packageName, wrpHandleName);
        }

        if (getLocalClass() != null) {
            packageName = GENERATED_PREFIX + BeanNaming.getPackageName(getLocalClass().getName());
            wrpLocalName = new String("JOnAS" + ejbIdentifier + "Local");
            fullWrpLocalName = BeanNaming.getClassName(packageName, wrpLocalName);
        }

        if (getHomeClass() != null) {
            packageName = GENERATED_PREFIX + BeanNaming.getPackageName(getHomeClass().getName());
            wrpHomeName = new String("JOnAS" + ejbIdentifier + "Home");
            fullWrpHomeName = BeanNaming.getClassName(packageName, wrpHomeName);
        }

        if (getLocalHomeClass() != null) {
            packageName = GENERATED_PREFIX + BeanNaming.getPackageName(getLocalHomeClass().getName());
            wrpLocalHomeName = new String("JOnAS" + ejbIdentifier + "LocalHome");
            fullWrpLocalHomeName = BeanNaming.getClassName(packageName, wrpLocalHomeName);
        }

        fullDerivedBeanName = getEjbClass().getName();
        derivedBeanName = BeanNaming.getBaseName(getEjbClass().getName());

        IorSecurityConfigMapping iorSecurityConfigMapping = jonasEjb.getIorSecurityConfig();
        if (iorSecurityConfigMapping != null) {
            processIorSecurityConfig(iorSecurityConfigMapping);
        }

        if (jonasEjb.getClusterReplicated() != null) {
            if (jonasEjb.getClusterReplicated().equalsIgnoreCase("True")) {
                clusterReplicated = true;
            } else if (jonasEjb.getClusterReplicated().equalsIgnoreCase("False")) {
                clusterReplicated = false;
            } else {
                throw new DeploymentDescException("Invalid cluster-replicated value for bean " + this.ejbName);
            }
        }
        cluster = jonasEjb.getCluster();
    }

    /**
     * Permit classes loading from subtypes. (needed for Stateless Session Beans
     * with service-endpoints). Needs to be overridden in subtypes.
     *
     * @param ce XML Element representing EJB Descriptor
     * @param loader ClassLoader used to load classes
     *
     * @throws DeploymentDescException when a class cannot be loaded
     */
    protected void loadExtraClasses(final CommonEjb ce, final ClassLoader loader) throws DeploymentDescException {
        // do nothing by default
    }

    /**
     * Permit Methods addition from subtypes Protected method that need to be
     * overridden in subclasses
     *
     * @param len method array length
     * @return new len value
     *
     * @throws DeploymentDescException when java reflection cannot be used on
     *         classes
     */
    protected int addEJBMethodDesc(final int len) throws DeploymentDescException {
        return len;
    }

    /**
     * Returns the parent Class for a method given an interface type.
     *
     * @param intfType type of the interface (Home/Remote/LocalHome/Local or
     *        ServiceEndpoint)
     *
     * @return the parent class for a method given an interface type
     *
     * @throws DeploymentDescException when intfType is unknown
     */
    protected Class getParentClass(final String intfType) throws DeploymentDescException {
        Class pClass = null;
        if (intfType.equals("Home")) {
            pClass = javax.ejb.EJBHome.class;
        } else if (intfType.equals("Remote")) {
            pClass = javax.ejb.EJBObject.class;
        } else if (intfType.equals("LocalHome")) {
            pClass = javax.ejb.EJBLocalHome.class;
        } else if (intfType.equals("Local")) {
            pClass = javax.ejb.EJBLocalObject.class;
        } else {
            throw new DeploymentDescException(intfType + " is invalid value for method-intf on bean " + ejbName);
        }
        return pClass;
    }

    /**
     * Gets an hashcode for this bean
     * Return hashcode for jndiname + jndi localname
     * @return a string for hashcode for jndiname + jndi localname
     */
    protected String getHashCodeForIdentifier() {
        String hash = "";
        if (getJndiName() != null) {
            hash += getJndiName();
        }
        if (getJndiLocalName() != null) {
            hash += getJndiLocalName();
        }
        return Integer.toString(hash.hashCode());
    }

    /**
     * Build a valid java identifier for the bean.
     * @return Returns a valid java identifier from the bean.
     */
    public String getIdentifier() {

        if (beanIdentification == null) {
            String identifier = getEjbName();
            identifier += getHashCodeForIdentifier();

            char[] tabChar = new char[identifier.length()];
            for (int i = 0; i < identifier.length(); i++) {
                if (!Character.isJavaIdentifierPart(identifier.charAt(i))) {
                    tabChar[i] = '_';
                } else {
                    tabChar[i] = identifier.charAt(i);
                }
            }
            beanIdentification = new String(tabChar);
        }
        return beanIdentification;
    }

    /**
     * Check if method throws RemoteException (or not).
     *
     * @param m the method to examine
     * @param shouldThrow boolean value indicating if the method should or
     *        shouldn't throw RemoteException
     *
     * @throws DeploymentDescException thrown for non-valid method
     */
    public void checkRemoteException(final java.lang.reflect.Method m, final boolean shouldThrow) throws DeploymentDescException {
        Class[] excepts = m.getExceptionTypes();
        for (int j = 0; j < excepts.length; j++) {
            if (RemoteException.class.isAssignableFrom(excepts[j])) {
                if (shouldThrow) {
                    return;
                } else {
                    throw new DeploymentDescException("Method " + m.getName() + " of " + m.getDeclaringClass()
                            + " should NOT throw RemoteException");
                }
            }
        }
        if (shouldThrow) {
            throw new DeploymentDescException("Method " + m.getName() + " of " + m.getDeclaringClass()
                    + " must throw RemoteException");
        } else {
            return;
        }

    }

    /**
     * Check if argument and return types are valid types for RMI-IIOP.
     * (Primitive types, remote objects, or non-remote objects that implement
     * the java.io.Serializable interface) Only a warning is logging if it's not
     * the case.
     *
     * @param m the methode to examine
     */
    public void checkValidTypesForRmi(final java.lang.reflect.Method m) {
        boolean isValid = true;
        Class[] paramTypes = m.getParameterTypes();
        for (int i = 0; i < paramTypes.length; i++) {
            if (!JavaType.isValidForRmi(paramTypes[i])) {
                isValid = false;
            }
        }
        if (!JavaType.isValidForRmi(m.getReturnType()) && !JavaType.isVoid(m.getReturnType())
                && !JavaType.isCollecOrEnum(m.getReturnType())) {
            // Allow Collection or Enumeration type (finder methods)
            isValid = false;
        }
        if (!isValid) {
            logger.log(BasicLevel.WARN, "Method " + m.getName() + " of " + m.getDeclaringClass()
                    + " may be have an invalid argument or return type for RMI");
        }
    }

    /**
     * Check that the bean descriptor is valid
     *
     * @throws DeploymentDescException thrown for non-valid bean
     */
    public void check() throws DeploymentDescException {
        // check business methods transaction attribute
        for (int i = 0; i < methodDesc.size(); i++) {
            checkTxAttribute(((MethodDesc) methodDesc.get(i)));
        }
        checkRunAsMapping();
    }

    /**
     * Check that the runAs role mapping is correct
     * @throws DeploymentDescException if role mapping is incorrect
     */
    public void checkRunAsMapping() throws DeploymentDescException {
        if (runAsPrincipalName != null) {
            // verify roles of run-as principal name
            String[] runAsPrincipalRoles = deploymentDesc.getRolesForRunAsPrincipal(runAsPrincipalName);
            // Check that the run-as role is included in principal roles
            if (runAsPrincipalRoles != null) {
                boolean isIncluded = false;
                for (int r = 0; r < runAsPrincipalRoles.length; r++) {
                    if (runAsPrincipalRoles[r].equals(runAsRole)) {
                        isIncluded = true;
                    }
                }
                if (!isIncluded) {
                    throw new DeploymentDescException("The run-as roles defined for the runas principal name '"
                            + runAsPrincipalName + "' does not contains the run-as role '"
                            + runAsRole + "' in bean '" + getEjbName() + ".");
                }
            }
        }
    }

    /**
     * Check that trans-attribute is valid for a bean's method.
     *
     * @param md MethodDesc to check
     *
     * @throws DeploymentDescException When MethodDesc is not valid
     */
    protected abstract void checkTxAttribute(MethodDesc md) throws DeploymentDescException;

    /**
     * Check that there are always corresponding role-name element in
     * security-role and method-permission elements.
     *
     * @param asd the AssemblyDescriptor used to check bean's role names
     *
     * @throws DeploymentDescException When verification fails
     */
    protected void verifyRoleName(final 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 = (String) j.next();
                    for (Iterator k = asd.getSecurityRoleList().iterator(); k.hasNext();) {
                        String srRoleName = ((SecurityRole) k.next()).getRoleName();
                        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 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() {
        return jndiName;
    }

    /**
     * Set 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
     *
     * @param jndiName Jndi name of the bean
     */
    public void setJndiName(final String jndiName) {
        this.jndiName = jndiName;
    }

    /**
     * Get the name to associate with the enterprise Bean in the JNDI name space
     * for local access (inside the same JOnAS Server)
     *
     * @return Jndi local name of the bean
     */
    public String getJndiLocalName() {
        return jndiLocalName;
    }

    /**
     * Set the name to associate with the enterprise Bean in the JNDI name space
     * for local access (inside the same JOnAS Server)
     *
     * @param jndiLocalName Jndi local name of the bean
     */
    public void setJndiLocalName(final String jndiLocalName) {
        this.jndiLocalName = jndiLocalName;
    }

    /**
     * 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 EJB 1.0 environment properties.
     *
     * @return Returns the bean's EJB 1.0 environment properties
     */
    public Properties getEjb10Environment() {
        Properties ret = new Properties(ejb10EnvProps);
        return ret;
    }

    /**
     * Get descriptor attached to a given method. Used by GenIC and JMdbEndpointFactory
     *
     * @param method Method from the Home/Remote/MessageListener interface
     * @return The method descriptor (never returns null)
     */
    public MethodDesc getMethodDesc(final java.lang.reflect.Method method) {

        if (!methodDescMap.containsKey(method)) {
            throw new Error(method.getName() + " is not a method of home/remote interfaces for bean " + getEjbName());
        }
        return (MethodDesc) methodDescMap.get(method);
    }

    /**
     * get an iterator for all MethodDesc of the bean.
     *
     * @return Returns an iterator for all MethodDesc of the bean
     */
    public Iterator getMethodDescIterator() {
        return methodDesc.iterator();
    }

    /**
     * get a MethodDesc from its index.
     *
     * @param index MethodDesc index
     *
     * @return Returns a MethodDesc from its index
     */
    public MethodDesc getMethodDesc(final int index) {
        return (MethodDesc) methodDesc.get(index);
    }

    /**
     * Gets the security-role-ref of the beans can access to the
     * EJBRoleRefPermission and role-link.
     *
     * @return the security-role-ref of the beans
     */
    public List getSecurityRoleRefDescList() {
        return securityRoleRefDescList;
    }

    /**
     * @return min size of the pool
     */
    public int getPoolMin() {
        return poolMin;
    }

    /**
     * @return max size of the cache
     */
    public int getCacheMax() {
        return cacheMax;
    }

    /**
     * @return the run-as role name
     */
    public String getRunAsRole() {
        return runAsRole;
    }

    /**
     * @return the transaction attribute for the ejbTimeout method
     */
    public int getTimerTxAttribute() {
        return timerTxAttribute;
    }

    /**
     * @return the security signature for the ejbTimeout method
     */
    public String getEjbTimeoutSignature() {
        return ejbTimeoutSignature;
    }

    /**
     * String representation of the object for test purpose
     *
     * @return String representation of this object
     */
    @Override
    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());
        IEnvEntryDesc[] envE = getEnvEntryDesc();
        for (int i = 0; i < envE.length; i++) {
            ret.append("\ngetEnvEntryDesc(" + i + ")=" + envE[i].toString());
        }
        IServiceRefDesc[] sr = getServiceRefDesc();
        for (int i = 0; i < sr.length; i++) {
            ret.append("\ngetServiceRefDesc(" + i + ")=" + sr[i].toString());
        }
        IResourceEnvRefDesc[] resEnvR = getResourceEnvRefDesc();
        for (int i = 0; i < resEnvR.length; i++) {
            ret.append("\ngetResourceEnvRefDesc(" + i + ")=" + resEnvR[i].toString());
        }
        IResourceRefDesc[] resR = getResourceRefDesc();
        for (int i = 0; i < resR.length; i++) {
            ret.append("\ngetResourceRefDesc(" + i + ")=" + resR[i].toString());
        }
        IEJBRefDesc[] ejbR = getEjbRefDesc();
        for (int i = 0; i < ejbR.length; i++) {
            ret.append("\ngetEjbRefDesc(" + i + ")=" + ejbR[i].toString());
        }
        IEJBLocalRefDesc[] ejbLR = getEjbLocalRefDesc();
        for (int i = 0; i < ejbLR.length; i++) {
            ret.append("\ngetEjbLocalRefDesc(" + i + ")=" + ejbLR[i].toString());
        }
        IMessageDestinationRefDesc[] mdR = getMessageDestinationRefDesc();
        for (int i = 0; i < mdR.length; i++) {
            ret.append("\ngetMessageDestinationRefDesc(" + i + ")=" + mdR[i].toString());
        }
        for (int i = 0; i < methodDesc.size(); i++) {
            MethodDesc md = (MethodDesc) methodDesc.get(i);
            ret.append("\ngetMethodDesc(" + i + ")=" + md.getClass().getName());
            ret.append(md.toString());
        }

        if (securityRoleRefDescList != null) {
            for (Iterator i = securityRoleRefDescList.iterator(); i.hasNext();) {
                SecurityRoleRefDesc sRoleRefDesc = (SecurityRoleRefDesc) i.next();
                ret.append("\nsecurity-role-ref, role-name = '" + sRoleRefDesc.getRoleName() + "', role-link = '"
                        + sRoleRefDesc.getRoleLink() + "'");
            }
        }
        ret.append("\ngetFullWrpRemoteName() = " + getFullWrpRemoteName());
        ret.append("\ngetFullWrpHomeName() = " + getFullWrpHomeName());
        ret.append("\ngetFullWrpLocalName() = " + getFullWrpLocalName());
        ret.append("\ngetFullWrpLocalHomeName() = " + getFullWrpLocalHomeName());
        ret.append("\ngetFullWrpHandleName() = " + getFullWrpHandleName());
        ret.append("\ngetFullDerivedBeanName() = " + getFullDerivedBeanName());
        ret.append("\ngetRunAsRole() = " + getRunAsRole());
        return ret.toString();
    }

    /**
     * MethodDesc constructor factory method to ovewrite
     *
     * @param meth the method to be wrapped into a MethodDesc instance
     * @param index index of the method inside the MethodDesc List
     *
     * @return Returns a new MethodDesc (or subclass)
     */
    protected MethodDesc newMethodDescInstance(final java.lang.reflect.Method meth, final Class classDef, final int index) {
        return new MethodDesc(this, meth, classDef, index);
    }

    /**
     * Add a new method descriptor to the bean
     *
     * @param meth method to add inside MethodDescs list
     *
     * @return the constructed MethodDesc
     */
    protected MethodDesc addMethodDesc(final java.lang.reflect.Method meth, final Class classDef) {
        MethodDesc md = newMethodDescInstance(meth, classDef, methodDesc.size());
        methodDesc.add(md);
        methodDescMap.put(meth, md);
        return md;
    }

    /**
     * @return Returns the full name of the wrapper class for the bean
     */
    public String getFullWrpRemoteName() {
        return fullWrpRemoteName;
    }

    /**
     * @return Returns the full name of the wrapper class for the bean
     */
    public String getFullWrpLocalName() {
        return fullWrpLocalName;
    }

    /**
     * @return Returns the name of the wrapper class for the bean
     */
    public String getWrpRemoteName() {
        return wrpRemoteName;
    }

    /**
     * @return Returns the name of the wrapper class for the bean
     */
    public String getWrpLocalName() {
        return wrpLocalName;
    }

    /**
     * @return Returns the full name of the Handle class for the bean
     */
    public String getFullWrpHandleName() {
        return fullWrpHandleName;
    }

    /**
     * @return Returns the name of the Handle class for the bean
     */
    public String getWrpHandleName() {
        return wrpHandleName;
    }

    /**
     * @return Returns the full name of the wrapper home class for the bean
     */
    public String getFullWrpHomeName() {
        return fullWrpHomeName;
    }

    /**
     * @return Returns the full name of the wrapper local home class for the bean
     */
    public String getFullWrpLocalHomeName() {
        return fullWrpLocalHomeName;
    }

    /**
     * @return Returns the name of the wrapper home class for the bean
     */
    public String getWrpHomeName() {
        return wrpHomeName;
    }

    /**
     * @return Returns the name of the wrapper local home class for the bean
     */
    public String getWrpLocalHomeName() {
        return wrpLocalHomeName;
    }

    /**
     * @return Returns the full name of the derived class of the bean
     */
    public String getFullDerivedBeanName() {
        return fullDerivedBeanName;
    }

    /**
     * @return Returns the name of the derived class of the bean
     */
    public String getDerivedBeanName() {
        return derivedBeanName;
    }

    /**
     * @return Returns the parent deployment descriptor
     */
    public DeploymentDesc getDeploymentDesc() {
        return deploymentDesc;
    }

    /**
     * Set the parent deployment descriptor
     *
     * @param deploymentDesc parent DeploymentDesc
     */
    public void setDeploymentDesc(final DeploymentDesc deploymentDesc) {
        this.deploymentDesc = deploymentDesc;
        logger = deploymentDesc.getLogger();
    }

    /**
     * Sort the MethodDesc list.
     *
     * @param al ArrayList to be sorted
     * @param begin begin index
     * @param length size of the list
     */
    private void orderMethodDesc(final ArrayList al, final int begin, final int length) {
        MethodDesc[] mds = new MethodDesc[length];
        for (int i = 0; i < length; i++) {
            mds[i] = (MethodDesc) al.get(begin + i);
        }
        Arrays.sort(mds, 0, length, new MethodDescComparator());
        for (int i = 0; i < length; i++) {
            al.set(begin + i, mds[i]);
            mds[i].setIndex(begin + i);
        }
    }

    /**
     * Compare 2 MethodDesc.
     */
    private class MethodDescComparator implements Comparator {

        /**
         * Compare 2 Object.
         *
         * @param o1 instance 1
         * @param o2 instance 2 to be compared to instance 1
         *
         * @return integer difference between the 2 instance
         */
        public int compare(final Object o1, final Object o2) {
            MethodDesc md1 = (MethodDesc) o1;
            MethodDesc md2 = (MethodDesc) o2;
            int res = md1.getMethod().getDeclaringClass().getName().compareTo(
                    md2.getMethod().getDeclaringClass().getName());
            if (res == 0) {
                res = md1.getMethod().getName().compareTo(md2.getMethod().getName());
                if (res == 0) {
                    // Same method name => compare the parameter types
                    Class[] p1 = md1.getMethod().getParameterTypes();
                    Class[] p2 = md2.getMethod().getParameterTypes();
                    res = p1.length - p2.length;
                    if (res == 0) {
                        //Same parameter size
                        for (int i = 0; i < p1.length && (res = p1[i].getName().compareTo(p2[i].getName())) == 0; i++) {
                            // compare each method
                        }
                    }
                }
            }
            return res;
        }
    }

    /**
     * @return the runAs principal name.
     */
    public String getRunAsPrincipalName() {
        return runAsPrincipalName;
    }

    /**
     * @return true if local interface has been defined in the DD
     */
    public boolean hasDefinedLocalInterface() {
        if (localhome == null) {
            return false;
        } else {
            return (!"javax.ejb.EJBLocalHome".equals(localhome.getName()));
        }
    }

    /**
     * Build sas component used for CSIv2 interop
     * @param iorSecurityConfigMapping CsiV2 ior configuration
     */
    private void processIorSecurityConfig(final IorSecurityConfigMapping iorSecurityConfigMapping) {

        // Transport
        TransportStruct transportStruct = new TransportStruct();
        // As
        AsStruct asStruct = new AsStruct();
        // Sas
        SasStruct sasStruct = new SasStruct();

        // Now fill SasComponent with given ior values
        TransportConfigMapping transportConfigMapping = iorSecurityConfigMapping.getTransportConfig();
        AsContextMapping asContextMapping = iorSecurityConfigMapping.getAsContext();
        SasContextMapping sasContextMapping = iorSecurityConfigMapping.getSasContext();

        // target requires (if required)
        int targetRequires = 0;
        if (transportConfigMapping.getIntegrity().equals("required")) {
            targetRequires |=  Integrity.value;
        }
        if (transportConfigMapping.getConfidentiality().equals("required")) {
            targetRequires |=  Confidentiality.value;
        }
        if (transportConfigMapping.getEstablishTrustInClient().equals("required")) {
            targetRequires |=  EstablishTrustInClient.value;
        }
        if (transportConfigMapping.getEstablishTrustInTarget().equals("required")) {
            targetRequires |=  EstablishTrustInTarget.value;
        }
        transportStruct.setTargetRequires(targetRequires);


        // target supports (supported or required)
        int targetSupports = 0;
        if (transportConfigMapping.getIntegrity().equals("supported") || transportConfigMapping.getIntegrity().equals("required")) {
            targetSupports |=  Integrity.value;
        }
        if (transportConfigMapping.getConfidentiality().equals("supported") || transportConfigMapping.getConfidentiality().equals("required")) {
            targetSupports |=  Confidentiality.value;
        }
        if (transportConfigMapping.getEstablishTrustInClient().equals("supported") || transportConfigMapping.getEstablishTrustInClient().equals("required")) {
            targetSupports |=  EstablishTrustInClient.value;
        }
        if (transportConfigMapping.getEstablishTrustInTarget().equals("supported") || transportConfigMapping.getEstablishTrustInTarget().equals("required")) {
            targetSupports |=  EstablishTrustInTarget.value;
        }
        transportStruct.setTargetSupports(targetSupports);


        // As struct (if it is needed)
        if (!asContextMapping.getAuthMethod().equals("none")) {
            asStruct.setTargetName(asContextMapping.getRealm());
            asStruct.setTargetSupports(EstablishTrustInClient.value);
            if (asContextMapping.getRequired().equals("true")) {
                asStruct.setTargetRequires(EstablishTrustInClient.value);

            }
        }

        // Sas struct (if supported)
        if (sasContextMapping.getCallerPropagation().equals("supported")) {
            sasStruct.enableGSSUPSupportedNamingMechanisms();
            sasStruct.setSupportedIdentityTypes(ITTAbsent.value | ITTAnonymous.value | ITTPrincipalName.value | ITTX509CertChain.value | ITTDistinguishedName.value);
            sasStruct.setTargetSupports(IdentityAssertion.value);
        }

        // and then, set our SAS component
        sasComponent = new SasComponent(transportStruct, asStruct, sasStruct);


    }

    /**
     * @return the sasComponent.
     */
    public SasComponent getSasComponent() {
        return sasComponent;
    }
    /**
     * @param sasComponent The sasComponent to set.
     */
    public void setSasComponent(final SasComponent sasComponent) {
        this.sasComponent = sasComponent;
    }

    /**
     * @return true if the bean has to be replicated over the cluster
     */
    public boolean isClusterReplicated() {
        return clusterReplicated;
    }


    /**
     * Set the cluster replicated attribute
     * @param replicated true if the replicated mode is enabled
     */
    public void setClusterReplicated(final boolean replicated) {
        this.clusterReplicated = replicated;
    }

    /**
     * @return the cluster
     */
    public Object getCluster() {
        return cluster;
    }

    /**
     * @param cluster the cluster to set
     */
    public void setCluster(final Object cluster) {
        this.cluster = cluster;
    }
}

