/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 1999-2007 Bull S.A.S.
 * 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: ResourceUtility.java 21566 2011-08-08 12:28:12Z cazauxj $
 * --------------------------------------------------------------------------
 */

package org.ow2.jonas.resource.internal;

import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.Vector;

import javax.management.ObjectName;
import javax.naming.BinaryRefAddr;
import javax.naming.Context;
import javax.naming.Reference;
import javax.naming.StringRefAddr;
import javax.resource.Referenceable;
import javax.resource.spi.ConnectionManager;
import javax.resource.spi.ManagedConnectionFactory;
import javax.resource.spi.ResourceAdapter;
import javax.resource.spi.ResourceAdapterAssociation;

import org.apache.commons.modeler.Registry;
import org.objectweb.util.monolog.api.BasicLevel;
import org.objectweb.util.monolog.api.Logger;
import org.ow2.jonas.deployment.ejb.ActivationConfigPropertyDesc;
import org.ow2.jonas.deployment.rar.ConfigPropertyDesc;
import org.ow2.jonas.deployment.rar.ConnectorDesc;
import org.ow2.jonas.deployment.rar.JdbcConnParamsDesc;
import org.ow2.jonas.deployment.rar.JonasConfigPropertyDesc;
import org.ow2.jonas.deployment.rar.JonasConnectorDesc;
import org.ow2.jonas.deployment.rar.PoolParamsDesc;
import org.ow2.jonas.jmx.JmxService;
import org.ow2.jonas.lib.management.javaee.J2eeObjectName;
import org.ow2.jonas.lib.naming.ComponentContext;
import org.ow2.jonas.lib.util.JNDIUtils;
import org.ow2.jonas.lib.util.Log;
import org.ow2.jonas.resource.internal.cm.ConnectionManagerImpl;
import org.ow2.jonas.resource.internal.cm.ConnectionManagerPoolParams;
import org.ow2.jonas.resource.internal.mbean.JCAConnectionFactory;
import org.ow2.jonas.resource.internal.mbean.JCAManagedConnectionFactory;
import org.ow2.jonas.resource.internal.mbean.JCAResource;
import org.ow2.jonas.resource.internal.naming.ResourceObjectFactory;
import org.ow2.jonas.tm.TransactionManager;

/**
 * ResourceUtility class
 * @author Eric Hardesty
 * Contributor(s):
 *
 */

public class ResourceUtility {

    /**
     * Main logger
     */
    private static Logger logger = null;
    /**
     * Config property setter logger
     */
    private static Logger setterLogger = null;
    /**
     * Management logger
     */
    private static Logger manageLogger = null;

    /**
     * Reference to a Registry object
     */
    private Registry oRegistry = null;

    /**
     * Reference to the jmx service
     */
    private JmxService jmx = null;

    // Properties for inits

    /**
     * JOnAS Connection Definition
     */
    public static final String JCD = "JCD";
    /**
     * JOnAS Activationspec
     */
    public static final String JAS = "JAS";
    /**
     * JOnAS Administrated Object
     */
    public static final String JAO = "JAO";

    /**
     * Default constructor
     *
     */
    public ResourceUtility() {
    }

    /**
     * Constructor
     *
     * @param log Logger main logger
     * @param sLog Logger setter logger
     * @param mLog Logger management logger
     */
    public ResourceUtility(final JmxService jmx,
                           final Logger log, final Logger sLog, final Logger mLog) {
        this.jmx = jmx;
        logger = log;
        setterLogger = sLog;
        manageLogger = mLog;
    }

    /**
     *
     * @param raCfg List
     * @param jRaCfg1 List
     * @param jRaCfg2 List
     * @return ConfigPropertyDesc array
     */
    public ConfigPropertyDesc [] buildConfigProperty(final List raCfg,
                                                     final List jRaCfg1,
                                                     final List jRaCfg2) {
        Vector cfVec = null;
        ConfigPropertyDesc[] configs = null;

        // Global config parameters for the Resource adapter
        if (raCfg != null) {
            for (Iterator i = raCfg.iterator(); i.hasNext();) {
                if (cfVec == null) {
                    cfVec = new Vector();
                }
                ConfigPropertyDesc cpd = (ConfigPropertyDesc) i.next();
                if (setterLogger.isLoggable(BasicLevel.DEBUG)) {
                    String name = cpd.getConfigPropertyName();
                    String val = cpd.getConfigPropertyValue();
                    setterLogger.log(BasicLevel.DEBUG, "Standard config: " + name + "=" + val);
                }
                cfVec.add(new ConfigPropertyDesc(cpd));
            }
        } else {  //Special case for configuring ActivationSpecs
            ActivationConfigPropertyDesc acp = null;
            ConfigPropertyDesc cp = null;
            if (jRaCfg1 != null) {
                for (Iterator i = jRaCfg1.iterator(); i.hasNext();) {
                    if (cfVec == null) {
                        cfVec = new Vector();
                    }
                    acp = (ActivationConfigPropertyDesc) i.next();
                    cp = new ConfigPropertyDesc();
                    cp.setConfigPropertyName(acp.getActivationConfigPropertyName());
                    cp.setConfigPropertyValue(acp.getActivationConfigPropertyValue());
                    cfVec.add(cp);
                }
            }

            if (cfVec == null) {
                if (jRaCfg2 != null) {
                    for (Iterator i = jRaCfg2.iterator(); i.hasNext();) {
                        if (cfVec == null) {
                            cfVec = new Vector();
                        }
                        acp = (ActivationConfigPropertyDesc) i.next();
                        cp = new ConfigPropertyDesc();
                        cp.setConfigPropertyName(acp.getActivationConfigPropertyName());
                        cp.setConfigPropertyValue(acp.getActivationConfigPropertyValue());
                        cfVec.add(cp);
                    }
                    if (cfVec != null) {
                        configs = new ConfigPropertyDesc[cfVec.size()];
                        cfVec.copyInto(configs);
                    }
                }
            } else {
                if (jRaCfg2 != null) {
                    boolean found = false;
                    for (Iterator i = jRaCfg2.iterator(); i.hasNext();) {
                        found = false;
                        acp = (ActivationConfigPropertyDesc) i.next();
                        String name = acp.getActivationConfigPropertyName();
                        String val = acp.getActivationConfigPropertyValue();
                        if (val != null && val.length() > 0) {
                            for (int j = 0; j < cfVec.size(); j++) {
                                cp = (ConfigPropertyDesc) cfVec.get(j);
                                if (name.equalsIgnoreCase(cp.getConfigPropertyName())) {
                                    cp.setConfigPropertyValue(val);
                                    cfVec.set(j, cp);
                                    found = true;
                                    break;
                                }
                            }
                            // This is the case where a new activation-config property is in
                            // the jonas specific dd
                            if (!found) {
                                cp = new ConfigPropertyDesc();
                                cp.setConfigPropertyName(name);
                                cp.setConfigPropertyValue(val);
                                cfVec.add(cp);
                            }
                        }
                    }
                }
                configs = new ConfigPropertyDesc[cfVec.size()];
                cfVec.copyInto(configs);
            }

            if (cfVec == null) {
                return null;
            }
            return configs;
        }

        if (cfVec == null) {
            return null;
        }

        configs = new ConfigPropertyDesc[cfVec.size()];
        cfVec.copyInto(configs);

        JonasConfigPropertyDesc jcpNext = null;
        if (jRaCfg2 != null) {
            for (Iterator i = jRaCfg2.iterator(); i.hasNext();) {
                jcpNext = (JonasConfigPropertyDesc) i.next();
                String name = jcpNext.getJonasConfigPropertyName();
                String val = jcpNext.getJonasConfigPropertyValue();
                if (val != null && val.length() > 0) {
                    for (int j = 0; j < configs.length; j++) {
                        if (name.equalsIgnoreCase(configs[j].getConfigPropertyName())) {
                            configs[j].setConfigPropertyValue(val);
                            break;
                        }
                    }
                }
            }
        }

        if (jRaCfg1 != null) {
            for (Iterator i = jRaCfg1.iterator(); i.hasNext();) {
                jcpNext = (JonasConfigPropertyDesc) i.next();
                String name = jcpNext.getJonasConfigPropertyName();
                String val = jcpNext.getJonasConfigPropertyValue();
                if (setterLogger.isLoggable(BasicLevel.DEBUG)) {
                    setterLogger.log(BasicLevel.DEBUG, "Jonas config: " + name + "=" + val);
                }
                if (val != null && val.length() > 0) {
                    for (int j = 0; j < configs.length; j++) {
                        if (name.equalsIgnoreCase(configs[j].getConfigPropertyName())) {
                            configs[j].setConfigPropertyValue(val);
                            break;
                        }
                    }
                }
            }
        }
        return configs;
    }

    /**
     *
     * @param inp String
     * @return boolean
     */
    private boolean checkLogEnabled(final String inp) {
        if (inp.equals("1") || inp.equalsIgnoreCase("on")
            || inp.equalsIgnoreCase("t") || inp.equalsIgnoreCase("true")
            || inp.equalsIgnoreCase("y") || inp.equalsIgnoreCase("yes")) {
            return true;
        }
         return false;
    }

    /**
     *
     * @param trans String
     * @param tm TransactionManager
     * @param logger Logger
     * @param poolLogger Logger
     * @param jndiName String
     * @param generic true if this RA is a generic (=abstract) RA
     * @return ConnectionManager
     * @throws Exception any exception
     */
    public ConnectionManager createConnectionManager(final String trans,
                                                     final TransactionManager tm,
                                                     final Logger logger,
                                                     final Logger poolLogger,
                                                     final String jndiName,
                                                     final boolean generic)
           throws Exception {

        ConnectionManagerImpl cm = new ConnectionManagerImpl(trans);

        Context c = new ComponentContext("");
        c.rebind(ConnectionManagerImpl.TRANSACTION_MANAGER, tm);

        // Set the MonologFactory into context of initialisation
        c.rebind(ConnectionManagerImpl.LOGGER, logger);
        c.rebind(ConnectionManagerImpl.POOL_LOGGER, poolLogger);
        c.rebind(ConnectionManagerImpl.JNDINAME, jndiName);

        // Initialize the ConnectionManager with the configured Context
        cm.init(c, generic);
        return cm;
    }

    /**
     * Process the ManagedConnectionFactory object
     * @param cmpp ConnectionManagerPoolParams
     * @param curLoader ClassLoader
     * @param rarName String
     * @param mcfc String
     * @param jndiName String
     * @param logEnabled String
     * @param logTopic String
     * @param cfgRaJonas ConfigPropertyDesc array
     * @param resAdp ResourceAdapter
     * @return Object
     * @throws Exception any exception
     */
    public Object processMCF(final ConnectionManagerPoolParams cmpp,
                             final ClassLoader curLoader,
                             final String rarName,
                             final String mcfc,
                             final String jndiName,
                             final String logEnabled,
                             final String logTopic,
                             final ConfigPropertyDesc [] cfgRaJonas,
                             final ResourceAdapter resAdp)  throws Exception {

        if (mcfc == null) {
            logger.log(BasicLevel.ERROR, "ResourceService.createRA:"
                       + " managedconnectionfactoryclass property not found");
            throw new Exception("configuration file incorrect");
        }

        if (jndiName == null || jndiName.length() == 0) {
            logger.log(BasicLevel.ERROR, "ResourceService.createRA: jndi-name not set in jonas-ra.xml");
            throw new Exception("configuration file incorrect");
        }

        // Instantiate into the current loader
        Class mcfClass = curLoader.loadClass(mcfc);
        ManagedConnectionFactory mcf =
            (ManagedConnectionFactory) mcfClass.newInstance();

        if (resAdp != null) {
            try {
                ((ResourceAdapterAssociation) mcf).setResourceAdapter(resAdp);
            } catch (ClassCastException ce) {
                // Not able to associate ResourceAdapter to MCF
            } catch (Exception ex) {
                logger.log(BasicLevel.ERROR, "ResourceService: Error setting ResourceAdapter class to ManagedConnectionFactory ("
                           + mcfc + ") for " + jndiName);
                throw ex;
            }
        }

        // Check if logging desired and the value of the desired topic
        if (logEnabled != null) {
            if (logger.isLoggable(BasicLevel.DEBUG)) {
                logger.log(BasicLevel.DEBUG, "log-enabled=" + logEnabled);
            }
            if (checkLogEnabled(logEnabled)) {
                if (logTopic != null && logTopic.length() > 0) {
                    if (logger.isLoggable(BasicLevel.DEBUG)) {
                        logger.log(BasicLevel.DEBUG, "log-topic=" + logTopic);
                    }
                    mcf.setLogWriter(Log.getLogWriter(logTopic));
                } else {
                    if (logger.isLoggable(BasicLevel.DEBUG)) {
                        logger.log(BasicLevel.DEBUG, "default log-topic=" + Log.JONAS_JCA_PREFIX);
                    }
                    mcf.setLogWriter(Log.getLogWriter(Log.JONAS_JCA_PREFIX));
                }
            }
        }

        if (setterLogger.isLoggable(BasicLevel.DEBUG)) {
            setterLogger.log(BasicLevel.DEBUG, jndiName + ": set config params");
        }
        processSetters(mcfClass, mcf, rarName, cfgRaJonas);

        // Process jdbc params found in cmpp if set
        // Works only with our jdbc RA, since method names are hardcoded here.
        if (cmpp.isJdbcConnSetUp()) {
            Object[] param = new Object[1];
            // JdbcConnLevel
            param[0] = cmpp.getJdbcConnLevel();
            try {
                Method method = mcfClass.getMethod("setJdbcConnLevel", new Class[] {Integer.TYPE});
                method.invoke(mcf, param);
                if (setterLogger.isLoggable(BasicLevel.DEBUG)) {
                    setterLogger.log(BasicLevel.DEBUG, jndiName + ": setJdbcConnLevel called");
                }
            } catch (Exception e) {
                setterLogger.log(BasicLevel.ERROR, "Could not invoke setJdbcConnLevel:" + e);
            }
            // JdbcConnTestStmt
            param[0] = cmpp.getJdbcConnTestStmt();
            try {
                Method method = mcfClass.getMethod("setJdbcConnTestStmt", new Class[] {String.class});
                method.invoke(mcf, param);
                if (setterLogger.isLoggable(BasicLevel.DEBUG)) {
                    setterLogger.log(BasicLevel.DEBUG, jndiName + ": setJdbcConnTestStmt called");
                }
            } catch (Exception e) {
                setterLogger.log(BasicLevel.ERROR, "Could not invoke setJdbcConnTestStmt:" + e);
            }
        }

        PrintWriter pw = mcf.getLogWriter();
        if (pw != null) {
            //Create a date format
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss z");
            String date = sdf.format(new Date());
            pw.println("MCF: output starting at " + date);
            pw.flush();
        }

        // Set hashCode for ManagedConnectionFactory
        try {
            mcf.hashCode();
        } catch (Exception ex) {
            String err = "Exception  in ManagedConnectionFactory.hashCode(): ";
            logger.log(BasicLevel.ERROR, err+ex);
        }


        return mcf;
    }


    /**
     *
     * @param cf Referenceable
     * @param jndiName String
     * @param rarName String
     * @param conn ConnectorDesc
     * @param jonasConn JonasConnectorDesc
     * @param factType String factory type
     * @param factOffset int factory offset
     * @param jcaResourceMBean JCAResource
     * @param jcaResourceName String
     * @param jDomain String of JOnAS domain name
     * @param jServer String of JOnAS server name
     * @param ictx Context
     * @param prop Properties
     * @throws Exception any Exception
     */
    public void registerMBean(final Referenceable cf, final String jndiName, final String rarName, final String rarFileName,
                              final ConnectorDesc conn, final JonasConnectorDesc jonasConn,
                              final String factType, final int factOffset,
                              final JCAResource jcaResourceMBean, final String jcaResourceName,
                              final String jDomain, final String jServer, final Context ictx, final Properties prop,
                              final String description, final ConnectionManagerImpl cm) throws Exception {

        try {
            Reference ref =
                new Reference(cf.getClass().getName(),
                              ResourceObjectFactory.class.getName(),
                              null);

            ref.add(new StringRefAddr(ResourceServiceConstants.JNDI_NAME, jndiName));
            ref.add(new StringRefAddr(ResourceServiceConstants.RAR_OBJNAME, rarName));
            ref.add(new StringRefAddr(ResourceServiceConstants.FACTORY_TYPE, factType));
            ref.add(new StringRefAddr(ResourceServiceConstants.FACTORY_OFFSET, "" + factOffset));
            //Put the connector objects
            byte[] bytes = JNDIUtils.getBytesFromObject(conn);
            if (bytes != null) {
                ref.add(new BinaryRefAddr(ResourceServiceConstants.RA_XML, bytes));
            }

            bytes = JNDIUtils.getBytesFromObject(jonasConn);
            if (bytes != null) {
                ref.add(new BinaryRefAddr(ResourceServiceConstants.JONAS_RA_XML, bytes));
            }

            cf.setReference(ref);
            ictx.rebind(jndiName, cf);

        } catch (Exception e) {
            logger.log(BasicLevel.ERROR, "ResourceService: Cannot register ResourceAdapter in naming with the name " + jndiName);
            logger.log(BasicLevel.ERROR, "ResourceService: Exception caught : " + e);
        }

        // check if jmx service reference is initialized before continuing
        if (jmx == null) {
            return;
        }
        // --------------------------
        // Register MBeans cf. JSR 77
        // --------------------------
        // Available ConnectionFactories and ManagedConnectionFactories
        // ------------------------------------------------------------
        // ConnectionFactory MBean
        // -----------------------
        String jcaConnectionFactoryName = jndiName;
        ObjectName onJCAConnectionFactory =
            J2eeObjectName.getJCAConnectionFactory(jDomain,
                    jcaResourceName,
                    jServer,
                    jcaConnectionFactoryName);
        JCAConnectionFactory jcaConnectionFactoryMBean =
            new JCAConnectionFactory(onJCAConnectionFactory.toString(), jndiName, rarFileName, prop, description, cm);
        jmx.registerModelMBean(jcaConnectionFactoryMBean, onJCAConnectionFactory);
        if (manageLogger.isLoggable(BasicLevel.DEBUG)) {
            manageLogger.log(BasicLevel.DEBUG, "JCAConnectionFactory created");
        }

        // Update the list of connection factories in the JCAResource MBean with the JCAConnectionFactory
        // MBean's OBJECT_NAME
        jcaResourceMBean.setConnectionFactory(onJCAConnectionFactory.toString());

        // ManagedConnectionFactory MBean
        // ------------------------------
        String jcaManagedConnectionFactoryName = getJcaMcfName(jcaConnectionFactoryName);
        ObjectName onJCAManagedConnectionFactory =
            J2eeObjectName.getJCAManagedConnectionFactory(jDomain,
                    jServer,
                    jcaManagedConnectionFactoryName);
        JCAManagedConnectionFactory jcaManagedConnectionFactoryMBean =
            new JCAManagedConnectionFactory(onJCAManagedConnectionFactory.toString());
        jmx.registerModelMBean(jcaManagedConnectionFactoryMBean, onJCAManagedConnectionFactory);
        if (manageLogger.isLoggable(BasicLevel.DEBUG)) {
            manageLogger.log(BasicLevel.DEBUG, "JCAManagedConnectionFactory created");
        }

        // Update the JCA ConnectionFactory with the JCA ManagedConnectionFactory
        jcaConnectionFactoryMBean.setManagedConnectionFactory(onJCAManagedConnectionFactory.toString());
        if (manageLogger.isLoggable(BasicLevel.DEBUG)) {
            manageLogger.log(BasicLevel.DEBUG, "JCAConnectionFactory updated");
        }
    }


    /**
     * Process setters on all config properties found
     * @param clsClass Class of the instance
     * @param clsObj instance where to apply the setters
     * @param fileName Name of the file being processed
     * @param cProp ConfigPropertyDesc array
     * @throws Exception any exception
     */
    public void processSetters(final Class clsClass,
                               final Object clsObj,
                               final String fileName,
                               final ConfigPropertyDesc [] cProp) throws Exception {

        // If no props, nothing to set.
        if (cProp == null) {
            return;
        }

        // For each Config Property
        for (int curParam = 0; curParam < cProp.length; curParam++) {
            ConfigPropertyDesc cpdesc = cProp[curParam];

            // Build method name and find type
            String fieldName = cpdesc.getConfigPropertyName();
            String methodName = "set" + fieldName.substring(0, 1).toUpperCase()
                + fieldName.substring(1);
            String fieldType = cpdesc.getConfigPropertyType();

            // Find matching method in mcf class
            Method method = null;
            Method[] m = clsClass.getMethods();
            for (int i = 0; i < m.length; i++) {
                if (m[i].getName().equals(methodName) &&
                    m[i].getParameterTypes().length == 1 &&
                    (fieldType == null || (m[i].getParameterTypes())[0].getName().equals(fieldType))) {
                    method = m[i];
                    break;
                }
            }
            if (method == null) {
                logger.log(BasicLevel.ERROR, "Method not found in class '" + clsClass + "': " + methodName);
                throw new Exception("method name '" + methodName + "' not found in class '" + clsClass + "'");
            }


            Class [] paramtype = method.getParameterTypes();
            Object[] param = new Object[1];

            String curValue = cpdesc.getConfigPropertyValue();
            if (setterLogger.isLoggable(BasicLevel.DEBUG)) {
                setterLogger.log(BasicLevel.DEBUG, "Processing Field Name: " + fieldName
                                 + " Type: " + fieldType + " Value: " + curValue);
            }

            if (paramtype[0].equals(java.lang.Integer.TYPE)
                || paramtype[0].equals(java.lang.Integer.class)) {
                param[0]  = new Integer(curValue);

            } else if (paramtype[0].equals(java.lang.Boolean.TYPE)
                       || paramtype[0].equals(java.lang.Boolean.class)) {
                param[0]  = new Boolean(curValue);

            } else if (paramtype[0].equals(java.lang.Double.TYPE)
                       || paramtype[0].equals(java.lang.Double.class)) {
                param[0]  = new Double(curValue);

            } else if (paramtype[0].equals(java.lang.Byte.TYPE)
                       || paramtype[0].equals(java.lang.Byte.class)) {
                param[0]  = new Byte(curValue);

            } else if (paramtype[0].equals(java.lang.Short.TYPE)
                       || paramtype[0].equals(java.lang.Short.class)) {
                param[0]  = new Short(curValue);

            } else if (paramtype[0].equals(java.lang.Long.TYPE)
                       || paramtype[0].equals(java.lang.Long.class)) {
                param[0]  = new Long(curValue);

            } else if (paramtype[0].equals(java.lang.Float.TYPE)
                       || paramtype[0].equals(java.lang.Float.class)) {
                param[0]  = new Float(curValue);

            } else if (paramtype[0].equals(java.lang.Character.TYPE)
                       || paramtype[0].equals(java.lang.Character.class)) {
                param[0]  = new Character(curValue.charAt(0));

            } else if (paramtype[0].equals(java.lang.String.class)) {
                param[0]  = curValue;
            } else {
                logger.log(BasicLevel.ERROR, "Type unsupported for setter method:" + methodName);
                throw new Exception("incorrect type for setter method ");
            }

            // invocation of the corresponding setter method on
            // class object instance
            try {
                method.invoke(clsObj, param);
            } catch (Exception e) {
                if (logger.isLoggable(BasicLevel.DEBUG)) {
                    logger.log(BasicLevel.DEBUG, "method "
                               + methodName
                               + " not found for " + fileName + "check its configuration ");
                }
            }
        }
    }

    /**
     * Set the PoolParams and the JdbcConnParams, if set.
     * @param pParams PoolParamsDesc
     * @param jConnParams JdbcConnParamsDesc
     * @param pool ConnectionManagerPoolParams
     * @return ConnectionManagerPoolParams
     * @throws Exception any exception
     */
    public ConnectionManagerPoolParams configurePoolParams (final PoolParamsDesc pParams,
                                                            final JdbcConnParamsDesc jConnParams,
                                                            final ConnectionManagerPoolParams pool)
               throws Exception {

        ConnectionManagerPoolParams cmpp = null;
        if (pool == null) {
            cmpp = new ConnectionManagerPoolParams();
        } else {
            cmpp = new ConnectionManagerPoolParams(pool);
        }
        String tmpPool = null;
        try {
            if (pParams != null) {
                if (pParams.getPoolInit() != null) {
                    tmpPool = pParams.getPoolInit();
                    if (tmpPool != null && tmpPool.length() > 0) {
                        cmpp.setPoolInit(Integer.parseInt(tmpPool));
                    }
                }
                if (pParams.getPoolMin() != null) {
                    tmpPool = pParams.getPoolMin();
                    if (tmpPool != null && tmpPool.length() > 0) {
                        cmpp.setPoolMin(Integer.parseInt(tmpPool));
                    }
                }
                if (pParams.getPoolMax() != null) {
                    tmpPool = pParams.getPoolMax();
                    if (tmpPool != null && tmpPool.length() > 0) {
                        cmpp.setPoolMax(Integer.parseInt(tmpPool));
                    }
                }
                if (pParams.getPoolMaxAge() != null) {
                    tmpPool = pParams.getPoolMaxAge();
                    if (tmpPool != null && tmpPool.length() > 0) {
                        cmpp.setPoolMaxAge(Long.parseLong(tmpPool));
                    }
                }
                if (pParams.getPoolMaxAgeMinutes() != null) {
                    tmpPool = pParams.getPoolMaxAgeMinutes();
                    if (tmpPool != null && tmpPool.length() > 0) {
                        cmpp.setPoolMaxAgeMinutes(Integer.parseInt(tmpPool));
                    }
                }
                if (pParams.getPoolMaxOpentime() != null) {
                    tmpPool = pParams.getPoolMaxOpentime();
                    if (tmpPool != null && tmpPool.length() > 0) {
                        cmpp.setPoolMaxOpentime(Integer.parseInt(tmpPool));
                    }
                }
                if (pParams.getPoolMaxWaiters() != null) {
                    tmpPool = pParams.getPoolMaxWaiters();
                    if (tmpPool != null && tmpPool.length() > 0) {
                        cmpp.setPoolMaxWaiters(Integer.parseInt(tmpPool));
                    }
                }
                if (pParams.getPoolMaxWaittime() != null) {
                    tmpPool = pParams.getPoolMaxWaittime();
                    if (tmpPool != null && tmpPool.length() > 0) {
                        cmpp.setPoolMaxWaittime(Integer.parseInt(tmpPool));
                    }
                }
                if (pParams.getPoolSamplingPeriod() != null) {
                    tmpPool = pParams.getPoolSamplingPeriod();
                    if (tmpPool != null && tmpPool.length() > 0) {
                        cmpp.setPoolSamplingPeriod(Integer.parseInt(tmpPool));
                    }
                }
                if (pParams.getPstmtMax() != null) {
                    tmpPool = pParams.getPstmtMax();
                    if (tmpPool != null && tmpPool.length() > 0) {
                        cmpp.setPstmtMax(Integer.parseInt(tmpPool));
                    }
                }
                if (pParams.getPstmtCachePolicy() != null) {
                    tmpPool = pParams.getPstmtCachePolicy();
                    if (tmpPool != null && tmpPool.length() > 0) {
                        cmpp.setPstmtCachePolicy(tmpPool);
                    }
                }
            }
           if (jConnParams != null) {
               if (jConnParams.isJdbcConnSetUp()) {
                   cmpp.setJdbcConnSetUp(true);
                   if (jConnParams.getJdbcCheckLevel() != null) {
                       tmpPool = jConnParams.getJdbcCheckLevel();
                       if (tmpPool != null && tmpPool.length() > 0) {
                           cmpp.setJdbcConnLevel(Integer.parseInt(tmpPool));
                       }
                   }
                   if (jConnParams.getJdbcTestStatement() != null) {
                       cmpp.setJdbcConnTestStmt(jConnParams.getJdbcTestStatement());
                   }
               }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
            logger.log(BasicLevel.ERROR, "Invalid Pool parameter from jonas-ra.xml:  Ensure that numeric values are used. " + tmpPool);
            throw new Exception("incorrect pool parameter ");
        }
        return cmpp;
    }

    /**
     * Return the parsed XML object relative to the section
     *
     * @param jonasConn JonasConnectorDesc object
     * @param id String id of the section
     * @param idOffset int offset within the section
     * @param oType String type of section
     * @return Object of parsed XML object
     * @throws Exception if the element is out of bound
     */
    public Object getJonasXML(final JonasConnectorDesc jonasConn,
                              final String id, final int idOffset, final String oType) throws Exception {
        try {
            Object obj = null;
            if (JCD.equals(oType)) {
                obj = jonasConn.getJonasConnectionDefinitionList().get(idOffset);
            } else if (JAS.equals(oType)) {
                obj = jonasConn.getJonasActivationspecList().get(idOffset);
            } else if (JAO.equals(oType)) {
                obj = jonasConn.getJonasAdminobjectList().get(idOffset);
            }
            return obj;
        } catch (IndexOutOfBoundsException e) {
            throw new Exception("Element " + oType + ", " + idOffset + " is not found in the jonas-ra.xml", e);
        }
    }

    /**
     * Return the JCA Managed Connection Factory name
     * @param jndiName String of jndi name
     * @return String of JCA Managed Connection Factory name
     */
    public String getJcaMcfName(final String jndiName) {
        return jndiName;
    }
}
