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


package org.objectweb.jonas.dbm;

import java.io.FileNotFoundException;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.List;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.Vector;

import javax.management.InstanceNotFoundException;
import javax.management.MBeanRegistrationException;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.modelmbean.ModelMBean;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

import org.apache.commons.modeler.ManagedBean;
import org.apache.commons.modeler.Registry;
import org.objectweb.jonas.common.JModule;
import org.objectweb.jonas.common.JProp;
import org.objectweb.jonas.common.Log;
import org.objectweb.jonas.jmx.J2eeObjectName;
import org.objectweb.jonas.jmx.JmxService;
import org.objectweb.jonas.jmx.JonasObjectName;
import org.objectweb.jonas.jtm.TransactionService;
import org.objectweb.jonas.management.JonasMBeanTools;
import org.objectweb.jonas.service.AbsServiceImpl;
import org.objectweb.jonas.service.ServiceException;
import org.objectweb.jonas.service.ServiceManager;
import org.objectweb.util.monolog.api.BasicLevel;
import org.objectweb.util.monolog.api.Logger;

/**
 * DatabaseService acts as a factory for the DataSource objects.
 * Its goal is to create such objects and to register them in JNDI
 *
 * @author Philippe Durieux
 *
 * Contributor(s):
 *
 * 00/18/04 Jun Inamori (j-office@osa.att.ne.jp)
 *          New implementation of unbindDataSources for closing correctly
 *          all connections at server shutdown.<p>
 * 03/01/14 Adriana Danes <p>
 *          Highlight Configuration properties
 *          Change createDataSource() signature : take additional argument, the datasource name
 *          Manage binded datasources (mapping of jndi name to datasource name)
 *          Use datasource name for naming MBeans (instead of jndi name)
 *          Modify MBean methods to take into account the previous points.<p>
 * 03/05/25 Introduce pool size configuration
 * 04/09/20 Create JSR77 MBeans JDBCResource, JDBCDataSource JDBCDriver
 */
public class DataBaseServiceImpl extends AbsServiceImpl implements DataBaseService, DataBaseServiceImplMBean {

    static private Logger logger = null;

    // List of DataSource in use.
    private Vector cmList = new Vector();    // ConnectionManager

    // Binded Datasource (jndi name -> datasource name)
    private Hashtable bindedDatasources = new Hashtable();

    // Names of the DataSource to create when starting the DataBase service
    private Vector dataSourceNames = new Vector();

    // Transaction Service reference
    private TransactionService transactionService = null;

    // Initial Context for Naming
    private Context ictx = null;

    // The DataBase service configuration parameters
    static final String DATASOURCES = "jonas.service.dbm.datasources";
    static final String CLASS = "jonas.service.dbm.class";

    // The Datasource configuration parameters
    static final String NAME = "datasource.name"; // JNDI name of the datasource
    static final String CLASSNAME = "datasource.classname";
    static final String DEF_CLASSNAME = "no class name";
    static final String URL = "datasource.url";
    static final String DEF_URL = "no url";
    static final String DESCRIPTION = "datasource.description";
    static final String DEF_DESCRIPTION = "no desc";
    static final String USERNAME = "datasource.username";
    static final String DEF_USERNAME = "";
    static final String PASSWORD = "datasource.password";
    static final String DEF_PASSWORD = "";
    static final String ISOLATIONLEVEL = "datasource.isolationlevel";
    static final String DEF_ISOLATIONLEVEL = "";
    static final String MAPPERNAME = "datasource.mapper";
    static final String DEF_MAPPERNAME = "rdb";

    // The ConnectionManager configuration parameters
    public static final String CONNCHECKLEVEL = "jdbc.connchecklevel";
    static final String DEF_CONNCHECKLEVEL = "1";
    public static final String CONNMAXAGE = "jdbc.connmaxage";
    static final String DEF_CONNMAXAGE = "1440";
    public static final String MAXOPENTIME = "jdbc.maxopentime";
    static final String DEF_MAXOPENTIME = "1440";
    public static final String CONNTESTSTMT = "jdbc.connteststmt";
    static final String DEF_CONNTESTSTMT = "SELECT 1";
    public static final String PSTMTMAX = "jdbc.pstmtmax";
    static final String DEF_PSTMTMAX = "12";
    static final String MINCONPOOL = "jdbc.minconpool";
    static final String DEF_MINCONPOOL = "0";
    static final String MAXCONPOOL = "jdbc.maxconpool";
    static final String DEF_MAXCONPOOL = "-1";
    static final String MAXWAITTIME = "jdbc.maxwaittime";
    static final String DEF_MAXWAITTIME = "10";
    static final String MAXWAITERS = "jdbc.maxwaiters";
    static final String DEF_MAXWAITERS = "1000";
    static final String SAMPLINGPERIOD = "jdbc.samplingperiod";
    static final String DEF_SAMPLINGPERIOD = "60";

    // JSR 77 variables
    // ----------------
    /**
     * Our naming convention for JDBCResource ObjectName (value of the 'name' key property)
     */
    public static final String JDBCResourceName = "JDBCResource";
    /**
     * Reference of the JDBCResource MBeans
     */
    private JDBCResource jdbcResourceMBean = null;
    private Registry oRegistry = null;
    private ManagedBean oManaged = null;
    private ModelMBean oMBean = null;
    private MBeanServer mbeanServer = null;
    private String domainName = null;
    private String serverName = null;


    // -------------------------------------------------------------------
    // Service Implementation
    // -------------------------------------------------------------------

    /**
     * Initialization of the DataBase service.
     * Configuration information is passed thru a Context object.
     */
    public void doInit(Context ctx) throws ServiceException {
        logger = Log.getLogger(Log.JONAS_DBM_PREFIX);
        // Avoid using NamingManager here: performance is not a goal here.
        try {
            ictx = new InitialContext();
        } catch (NamingException e) {
            logger.log(BasicLevel.ERROR, "Cannot create initial context when DataBase service initializing");
            throw new ServiceException("Cannot create initial context when DataBase service initializing", e);
        }

        // Get the list of the datasource names
        String ds = null;
        try {
            ds = (String) ctx.lookup(DATASOURCES);
        } catch (NamingException e) {
            // No problem if there is no value for 'datasources'
            logger.log(BasicLevel.INFO, "No value set for Datasource:" + e);
        }
        if (ds != null) {
            StringTokenizer st = new StringTokenizer(ds, ",");
            while (st.hasMoreTokens()) {
                dataSourceNames.add(st.nextToken().trim());
            }
        }

        // Get un reference to the Transaction service
        try {
            transactionService =
                (TransactionService) ServiceManager.getInstance().getTransactionService();
        } catch (ServiceException se) {
            logger.log(BasicLevel.ERROR, "Cannot get the Transaction service: ");
            throw se;
        } catch (Exception e) {
            logger.log(BasicLevel.ERROR, "Cannot get the Transaction service");
            throw new ServiceException("Cannot get the Transaction service: ", e);
        }

        // Get the JMX Server via JMX Service
        try {
            mbeanServer =
                ((JmxService) ServiceManager.getInstance().getJmxService()).getJmxServer();
        } catch (Exception e) {
            // the JMX service may not be started
            mbeanServer = null;
        }
        // Use Jakarta Common Modeler API
        oRegistry = JonasMBeanTools.getRegistry();
        if (logger.isLoggable(BasicLevel.DEBUG)) {
            logger.log(BasicLevel.DEBUG, "DataBaseService initialized");
        }
    }

    /**
     * Starting DataBase service
     * Initialization of the service is already done.
     */
    public void doStart() throws ServiceException {
        logger.log(BasicLevel.DEBUG, "Starting DataBase service");
        /*
         * Create JDBCResource MBean associated by the dbm service.
         * This bean has to be created before the creation of the connection manager objects
         * beacuse the creation of cms implies the creation of JDBCDataSource MBeans to
         * be attached to the JDBCResource MBeans
         */
        domainName = getDomainName();
        serverName = getJonasServerName();
        if (mbeanServer != null) {
            try {
                ObjectName onJDBCResource = J2eeObjectName.JDBCResource(domainName, serverName, JDBCResourceName);
                jdbcResourceMBean = new JDBCResource(onJDBCResource.toString());
                oManaged = oRegistry.findManagedBean("JDBCResource");
                oMBean = oManaged.createMBean(jdbcResourceMBean);
                if (logger.isLoggable(BasicLevel.DEBUG)) {
                    logger.log(BasicLevel.DEBUG, "JDBResource J2EEResource created");
                }
                mbeanServer.registerMBean(oMBean, onJDBCResource);
            } catch (Exception e) {
                logger.log(BasicLevel.ERROR, "JOnAS: Cannot register JDBCResource mBean", e);
            }
        }

        // Creates connection managers for each datasource
        String dsName = null;
        for (int i = 0; i < dataSourceNames.size(); i++) {
            dsName = (String) dataSourceNames.elementAt(i);
            try {
                JProp prop = JProp.getInstance(dsName);
                if (logger.isLoggable(BasicLevel.DEBUG)) {
                    logger.log(BasicLevel.DEBUG, "Creating Datasource " + dsName);
                }
                createDataSource(dsName, prop.getConfigFileEnv());
            } catch (Exception e) {
                JProp.removeInstance(dsName);
                logger.log(BasicLevel.ERROR, "JOnAS: Cannot create datasource: '" + dsName + "'", e);
                logger.log(BasicLevel.ERROR, "Please check if " + dsName + ".properties is available");
            }
        }

        // Register DataBaseService MBean
        try {
            mbeanServer.registerMBean(this, JonasObjectName.databaseService());
        } catch (ServiceException se) {
            // Jmx Service not available, do nothing
        } catch (Exception e) {
            logger.log(BasicLevel.ERROR, "DataBaseService: Cannot start the DataBase service");
            throw new ServiceException("DataBaseService: Cannot start the DataBase service", e);
        }
        if (logger.isLoggable(BasicLevel.DEBUG)) {
            logger.log(BasicLevel.DEBUG, "DataBaseService started");
        }
    }

    /**
     * Stopping DataBase service
     * Unbind Datasource
     */
    public void doStop() throws ServiceException {
        try {
            unbindDataSources();
        } catch (NamingException e) {
            logger.log(BasicLevel.ERROR, "Cannot unbind datasources");
            throw new ServiceException("Cannot unbind datasources ", e);
        }

        try {
            if (mbeanServer != null) {
                // unregister DatabaseService MBean
                mbeanServer.unregisterMBean(JonasObjectName.databaseService());
                // unregister JDBCResource
                ObjectName onJDBCResource = J2eeObjectName.JDBCResource(domainName, serverName, JDBCResourceName);
                mbeanServer.unregisterMBean(onJDBCResource);
            }
        } catch (ServiceException se) {
            // Jmx Service not available, do nothing
        } catch (Exception e) {
            logger.log(BasicLevel.ERROR, "EJBService: Cannot stop the DataBase service");
            throw new ServiceException("DataBaseService: Cannot stop the DataBase service",e);
        }
        if (logger.isLoggable(BasicLevel.DEBUG)) {
            logger.log(BasicLevel.DEBUG, "DataBaseService stopped");
        }
    }

    // -------------------------------------------------------------------
    // DataBaseService Implementation
    // -------------------------------------------------------------------

    /**
     * Creates a ConnectionManager (implementation of sql.dataSource).
     * @param datasourceName - datasource name
     * @param dsd - a set of properties that describes a dataSource and the ConnectionPool
     */
    public void createDataSource(String datasourceName, Properties dsd) throws Exception {
        // Get properties common to all DataSource types
        String dsName = dsd.getProperty(NAME); // JDNI name of the datasource
        if (dsName != null) {
            dsName = dsName.trim();
        } else {
            logger.log(BasicLevel.ERROR, "");
            throw new ServiceException("Cannot create datasource as JNDI name not provided");
        }
        String className = dsd.getProperty(CLASSNAME, DEF_CLASSNAME).trim();
        String url = dsd.getProperty(URL, DEF_URL).trim();
        String description = dsd.getProperty(DESCRIPTION, DEF_DESCRIPTION).trim();
        String user = dsd.getProperty(USERNAME, DEF_USERNAME).trim();
        String password = dsd.getProperty(PASSWORD, DEF_PASSWORD).trim();
        String connCheckLevel = dsd.getProperty(CONNCHECKLEVEL, DEF_CONNCHECKLEVEL).trim();
        String connMaxAge = dsd.getProperty(CONNMAXAGE, DEF_CONNMAXAGE).trim();
        String maxOpenTime = dsd.getProperty(MAXOPENTIME, DEF_MAXOPENTIME).trim();
        String minconpool = dsd.getProperty(MINCONPOOL, DEF_MINCONPOOL).trim();
        String maxconpool = dsd.getProperty(MAXCONPOOL, DEF_MAXCONPOOL).trim();
        String maxwaittime = dsd.getProperty(MAXWAITTIME, DEF_MAXWAITTIME).trim();
        String maxwaiters = dsd.getProperty(MAXWAITERS, DEF_MAXWAITERS).trim();
        String samplingperiod = dsd.getProperty(SAMPLINGPERIOD, DEF_SAMPLINGPERIOD).trim();
        String defaultStatement = dsd.getProperty(CONNTESTSTMT, DEF_CONNTESTSTMT).trim();
        String pstmtmax = dsd.getProperty(PSTMTMAX, DEF_PSTMTMAX).trim();

        // Create ConnectionManager (JOnAS DataSource)
        if (logger.isLoggable(BasicLevel.DEBUG)) {
            logger.log(BasicLevel.DEBUG, "create JOnAS ConnectionManager corresponding to data source " + datasourceName + " with JNDI name " + dsName);
        }
        ConnectionManager ds = new ConnectionManager();

        // Initialize ConnectionManager
        ds.setDatasourceName(datasourceName); // set datasource name
        ds.setDSName(dsName); // set jndi name
        ds.setUrl(url);
        ds.setClassName(className);
        ds.setUserName(user);
        ds.setPassword(password);
        ds.setTransactionIsolation(dsd.getProperty(ISOLATIONLEVEL, DEF_ISOLATIONLEVEL).trim());
        ds.setMapperName(dsd.getProperty(MAPPERNAME, DEF_MAPPERNAME).trim());
        ds.setDataSourceDescription(description);
        ds.poolConfigure(connCheckLevel, connMaxAge, maxOpenTime, defaultStatement, pstmtmax,
                         minconpool, maxconpool, maxwaittime, maxwaiters, samplingperiod);

        // Register ConnectionManager in JNDI and in internal data structures
        cmList.addElement(ds);
        ictx.rebind(dsName, ds);
        // allows for getting the data source name from the jndi name
        bindedDatasources.put(dsName, datasourceName);
        logger.log(BasicLevel.INFO, "Mapping ConnectionManager " + url + " on " + dsName);

        try {
            // --------------------------
            // Register MBeans cf. JSR 77
            // --------------------------
            if (mbeanServer != null) {
                // Available DataSources and Drivers
                // ------------------------------------------------------------
                // DataSource MBean
                // -----------------------
                String jdbcDataSourceName = datasourceName;
                ObjectName onJDBCDataSource =
                    J2eeObjectName.getJDBCDataSource(domainName,
                                                     serverName,
                                                     jdbcDataSourceName);
                JDBCDataSource jdbcDataSourceMBean = new JDBCDataSource(onJDBCDataSource.toString(), ds);
                oManaged = oRegistry.findManagedBean("JDBCDataSource");
                oMBean = oManaged.createMBean(jdbcDataSourceMBean);
                if (logger.isLoggable(BasicLevel.DEBUG)) {
                    logger.log(BasicLevel.DEBUG, "JDBCDataSource created");
                }
                mbeanServer.registerMBean(oMBean, onJDBCDataSource);

                // Update the list of dataSources in the JDBCResource MBean with the JDBCDataSource
                // MBean's OBJECT_NAME
                jdbcResourceMBean.addJdbcDataSource(onJDBCDataSource.toString());

                // JDBCDriver MBean
                // ------------------------------
                String jdbcDriverName = "aJDBCDriver-" + jdbcDataSourceName; // TO BE IMPLEMENTED
                ObjectName onJDBCDriver =
                    J2eeObjectName.getJDBCDriver(domainName,
                                                 serverName,
                                                 jdbcDriverName);
                JDBCDriver jdbcDriverMBean =
                    new JDBCDriver(onJDBCDriver.toString());
                jdbcDriverMBean.setDriverClassName(className);
                oManaged = oRegistry.findManagedBean("JDBCDriver");
                oMBean = oManaged.createMBean(jdbcDriverMBean);
                if (logger.isLoggable(BasicLevel.DEBUG)) {
                    logger.log(BasicLevel.DEBUG, "JDBCDriver created");
                }
                mbeanServer.registerMBean(oMBean, onJDBCDriver);

                // Update the JDBC DataSource with the JDBC Driver
                jdbcDataSourceMBean.setJdbcDriver(onJDBCDriver.toString());
                if (logger.isLoggable(BasicLevel.DEBUG)) {
                    logger.log(BasicLevel.DEBUG, "JDBCDataSource updated");
                }

            } // end JMX registration
        } catch (ServiceException se) {
            // Jmx Service not available, do nothing
        }

    }

    /**
     * Unbind dataSource names from the registry, unregister MBeans
     */
    public void unbindDataSources() throws NamingException {

        logger.log(BasicLevel.DEBUG, "");

        try {
            if (cmList.size() > 0) {
                String dsn = null;
                for (Enumeration lk = cmList.elements(); lk.hasMoreElements();) {
                    ConnectionManager cm = (ConnectionManager) lk.nextElement();
                    cm.closeAllConnection();
                    dsn = cm.getDSName();
                    ictx.unbind(dsn);
                    bindedDatasources.remove(dsn);
                }
            }
        } catch (NamingException e) {
            logger.log(BasicLevel.ERROR, "cannot unbind DataSources", e);
            throw e;
        }

        // --------------------------
        // unregister MBeans cf. JSR 77
        // --------------------------
        if (mbeanServer != null) {
            try {
                // Get JDBCDataSource OBJECT_NAMEs
                String[] ons = jdbcResourceMBean.getJdbcDataSources();
                ObjectName onJDBCDataSource = null;
                ObjectName onJDBCDriver = null;
                for (int i = 0; i < ons.length; i++) {
                    onJDBCDataSource = ObjectName.getInstance(ons[i]);
                    String jdbcDriverName = (String) mbeanServer.getAttribute(onJDBCDataSource, "jdbcDriver");
                    onJDBCDriver = new ObjectName(jdbcDriverName);
                    // Unregister JDBCDataSource MBean
                    mbeanServer.unregisterMBean(onJDBCDataSource);
                    // Unregister JDBCDriver MBean
                    mbeanServer.unregisterMBean(onJDBCDriver);
                    // Update the list of dataSources in the JDBCResource MBean
                    jdbcResourceMBean.removeJdbcDataSource(onJDBCDataSource.toString());
                }
            } catch (MalformedObjectNameException ma) {
                logger.log(BasicLevel.ERROR, "Cannot cleanly unregister DataSource", ma);
            } catch (MBeanRegistrationException mr) {
                logger.log(BasicLevel.ERROR, "Cannot cleanly unregister DataSource", mr);
            } catch (InstanceNotFoundException infe) {
                logger.log(BasicLevel.ERROR, "Cannot cleanly unregister DataSource", infe);
            } catch (Exception e) {
                logger.log(BasicLevel.ERROR, "Cannot cleanly unregister DataSource", e);
            }
        }
    }

    /**
     * get ConnectionManager for the datasource having this JNDI name.
     */
    public ConnectionManager getConnectionManager(String dsname) {
        ConnectionManager cm = null;
        if (cmList.size() > 0) {
            for (Enumeration lk = cmList.elements(); lk.hasMoreElements(); ) {
                cm = (ConnectionManager)lk.nextElement();
                if (cm.getDSName().equals(dsname)) {
                    return cm;
                }
            }
        }
        return null;
    }

    /**
     * return the list of the datasources
     * @return
     */
    public Collection getDSList() {
        return cmList;
    }

    //------------------------------------------------------------------------------------------

    /**
     * MBean method:
     * @return the list of properties files describing datasources found in JONAS_BASE/conf
     */
    public List getDataSourcePropertiesFiles() throws Exception {
        return JModule.getDatasourcePropsInDir();
    }

    /**
     * MBean method:
     * @return Integer Total Number of Datasource available in JOnAS
     */
    public Integer getCurrentNumberOfDataSource() {
        return new Integer(cmList.size());
    }

    /**
     * MBean method:
     * @return Integer Total Number of JDBC connection open
     */
    public Integer getTotalCurrentNumberOfJDBCConnectionOpen(){
        int result = 0;
        if (cmList.size() > 0) {
            for (Enumeration lk = cmList.elements(); lk.hasMoreElements(); ) {
                ConnectionManager cm = (ConnectionManager)lk.nextElement();
                result += cm.getPool().getCurrentOpened();
            }
        }
        return new Integer(result);
    }

    /**
     * MBean method:
     * @return true if the datasource having thid jndi name is loadd
     */
    public boolean isLoadedDataSource(String dsName) {
        boolean result = false;
        if (cmList.size() > 0) {
            for (Enumeration lk = cmList.elements(); lk.hasMoreElements(); ) {
                ConnectionManager cm = (ConnectionManager)lk.nextElement();
                if (cm.getDatasourceName().equals(dsName))
                    return true;
            }
        }
        return result;
    }

    /**
     * MBean method:
     * @param name of the data source to unload
     */
    public void unloadDataSource(String name) {
        logger.log(BasicLevel.DEBUG, "");
        try {
            if (cmList.size() > 0) {
                for (Enumeration lk = cmList.elements(); lk.hasMoreElements();) {
                    ConnectionManager cm = (ConnectionManager) lk.nextElement();
                    String dsName = cm.getDatasourceName();
                    String jndiName = cm.getDSName();
                    if (dsName.equals(name)) {
                        // unbind data source
                        cm.closeAllConnection();
                        ictx.unbind(jndiName);
                        // remove datasource
                        cmList.remove(cm);
                        // remove JProp instance corresponding to this datasource in order to
                        // allow re-create in case its re-loaded
                        JProp.removeInstance(dsName);
                        if (mbeanServer != null) {
                            ObjectName onJDBCDataSource = J2eeObjectName.getJDBCDataSource(domainName, serverName, dsName);
                            String jdbcDriverName = (String) mbeanServer.getAttribute(onJDBCDataSource, "jdbcDriver");
                            ObjectName onJDBCDriver = new ObjectName(jdbcDriverName);
                            // Unregister JDBCDataSource MBean
                            mbeanServer.unregisterMBean(onJDBCDataSource);
                            // Unregister JDBCDriver MBean
                            mbeanServer.unregisterMBean(onJDBCDriver);
                            // Update the list of dataSources in the JDBCResource MBean
                            jdbcResourceMBean.removeJdbcDataSource(onJDBCDataSource.toString());
                        }
                        return;
                    }
                }
            }
        }  catch (Exception e) {
            logger.log(BasicLevel.ERROR, "cannot unload DataSources", e);
        }
    }

    /**
     * MBean method:
     * @return datasource properties from a local file
     */
    public Properties getDataSourcePropertiesFile(String dsFile) throws Exception {
        try {
            return JProp.getInstance(dsFile).getConfigFileEnv();

        } catch (Exception e) {
            if (e instanceof FileNotFoundException) {
                logger.log(BasicLevel.ERROR, "Please check if '"+dsFile+".properties' is available in JONAS_BASE/conf/ directory");
            } else {
                logger.log(BasicLevel.ERROR, "Error occured when reading file " + dsFile);
            }
            throw e;
        }
    }

    /**
     * MBean method:
     * load a new datasource
     * @param name datasource name
     * @param prop datasource properties
     * @param loadFromFile if false the datasource creation was dynamicaly invoked by a management
     * operation providing the properties in the prop object.
     * @throws ServiceException datasource could not be created
     */
    public void loadDataSource(String name, Properties prop, Boolean loadFromFile) throws ServiceException {
        boolean fromFile = loadFromFile.booleanValue();

        if (fromFile) {
            logger.log(BasicLevel.DEBUG, "Load data source named " + name + " from file");
        } else {
            logger.log(BasicLevel.DEBUG, "Load data source named " + name + " from form");
            if (isLoadedDataSource(name)) {
                logger.log(BasicLevel.DEBUG, "This data source, " + name + " is already loaded ; Unload it !");
                unloadDataSource(name);
            }
            try {
                logger.log(BasicLevel.DEBUG, "Call getInstance on JProp in order to create the properties file");
                JProp.getInstance(name, prop);
            } catch (Exception e) {
                logger.log(BasicLevel.ERROR, "Cannot create datasource " + name + " as cannot create properties file");
                throw new ServiceException("DatabaseService: Cannot create datasource '" + name + "'", e);
            }
        }

        try {
            logger.log(BasicLevel.DEBUG, "Call method to create a data source");
            createDataSource(name, prop);
            logger.log(BasicLevel.DEBUG, "New data source created");
        } catch (Exception e) {
            logger.log(BasicLevel.ERROR, "Cannot create datasource '" + name + "'.");
            if (fromFile) {
                JProp.removeInstance(name);
            } else {
                JProp.deleteInstance(name);
            }
            throw new ServiceException("DatabaseService: Cannot create datasource: " + name + "'", e);
        }
    }

    /**
     * MBean method allowing to determine the datasource name from its jndi name
     * @param jndiName The jndi name of a datasource
     * @return The datasource name
     */
    public String getDatasourceName(String jndiName) {
        return (String) bindedDatasources.get(jndiName);
    }

}

