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

package org.ow2.jonas.dbm.internal;

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

import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;

import org.objectweb.util.monolog.api.BasicLevel;
import org.objectweb.util.monolog.api.Logger;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.util.tracker.BundleTracker;
import org.ow2.jonas.dbm.DataBaseService;
import org.ow2.jonas.dbm.internal.cm.ConnectionManager;
import org.ow2.jonas.dbm.internal.mbean.JDBCDataSource;
import org.ow2.jonas.dbm.internal.mbean.JDBCDriver;
import org.ow2.jonas.dbm.internal.mbean.JDBCResource;
import org.ow2.jonas.dbm.internal.osgi.JDBCDriverBundleTrackerCustomizer;
import org.ow2.jonas.jmx.JmxService;
import org.ow2.jonas.lib.bootstrap.JProp;
import org.ow2.jonas.lib.execution.ExecutionResult;
import org.ow2.jonas.lib.execution.IExecution;
import org.ow2.jonas.lib.execution.RunnableHelper;
import org.ow2.jonas.lib.management.javaee.J2eeObjectName;
import org.ow2.jonas.lib.service.AbsServiceImpl;
import org.ow2.jonas.lib.util.JModule;
import org.ow2.jonas.lib.util.JonasObjectName;
import org.ow2.jonas.lib.util.Log;
import org.ow2.jonas.registry.RegistryService;
import org.ow2.jonas.service.ServiceException;
import org.ow2.jonas.tm.TransactionService;

/**
 * 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 bound 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 JOnASDataBaseManagerService extends AbsServiceImpl
                                         implements DataBaseService,
                                                    JOnASDataBaseManagerServiceMBean,
                                                    DBMConstants {

    /**
     * logger.
     */
    private static Logger logger = Log.getLogger(Log.JONAS_DBM_PREFIX);

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

    /**
     * Bound Datasources (jndi name -> datasource name).
     */
    private Map<String, String> boundDatasources = new Hashtable<String, String>();

    /**
     * DataSource names to create when starting the DataBase service.
     */
    private List<String> dataSourceNames = new Vector<String>();

    /**
     * JMX Service reference.
     */
    private JmxService jmxService = null;

    /**
     * Transaction service reference.
     */
    private TransactionService txService = null;

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

    /**
     * RegistryService.
     */
    private RegistryService registryService;

    // Admin code
    // ----------
    /**
     * Our naming convention for JDBCResource ObjectName (value of the 'name' key property).
     */
    public static final String JDBC_RESOURCE_NAME = "JDBCResource";

    /**
     * Reference of the JDBCResource MBean.
     */
    private JDBCResource jdbcResourceMBean = null;

    /**
     * OSGi bundle context.
     */
    private BundleContext bundleContext = null;

    /**
     * OSGi Bundle tracker for SQL Driver.
     */
    private BundleTracker osgiBundlesTracker= null;

    /**
     * Defaut constructor with the given bundle context.
     * @param bundleContext the OSGi bundle context
     */
    public JOnASDataBaseManagerService(final BundleContext bundleContext) {
        this.bundleContext = bundleContext;
    }

    /**
     * @param datasources datasources to deploy at startup.
     */
    public void setDatasources(final String datasources) {
        dataSourceNames = convertToList(datasources);
    }

    /**
     * Starting DataBase service Initialization of the service is already done.
     * @throws ServiceException exception
     */
    @Override
    public void doStart() throws ServiceException {
        logger.log(BasicLevel.DEBUG, "Starting DataBase service");

        // Get the InitialContext in an execution block
        IExecution<InitialContext> ictxGetter = new IExecution<InitialContext>() {
            public InitialContext execute() throws Exception {
                return getRegistryService().getRegistryContext();
            }
        };

        // Execute
        ExecutionResult<InitialContext> ictxResult = RunnableHelper.execute(getClass().getClassLoader(), ictxGetter);
        // Throw an ServiceException if needed
        if (ictxResult.hasException()) {
            logger.log(BasicLevel.ERROR, "Cannot create initial context when DataBase service initializing");
            throw new ServiceException("Cannot create initial context when DataBase service initializing", ictxResult
                    .getException());
        }
        // Store the ref
        ictx = ictxResult.getResult();

        // TODO, When mail service will become a bundle, we could use
        // the meta-data located in META-INF/mbeans-descriptors.xml
        jmxService.loadDescriptors(getClass().getPackage().getName(), getClass().getClassLoader());

        /**
         *  DataBase service administration
         */
        registerDbmServiceMBean(this, getDomainName());
        /**
         * JDBCResource MBean 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
         */
        jdbcResourceMBean = registerJdbcResourceMBean(getDomainName(), getJonasServerName(), JDBC_RESOURCE_NAME);

        // Creates connection managers for each datasource
        String dsName = null;
        for (int i = 0; i < dataSourceNames.size(); i++) {
            dsName = dataSourceNames.get(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");
            }
        }

        // Start the OSGi JDBC Driver tracker
        osgiBundlesTracker = new BundleTracker(bundleContext, Bundle.ACTIVE, new JDBCDriverBundleTrackerCustomizer(bundleContext, txService));
        osgiBundlesTracker.open();

        logger.log(BasicLevel.INFO, "DBM Service started");
    }

    /**
     * Stopping DataBase service.
     * Unbind Datasource
     * @throws ServiceException exception
     */
    @Override
    public void doStop() throws ServiceException {

        // Stop tracking
        if (osgiBundlesTracker != null) {
            osgiBundlesTracker.close();
        }

        // Stop OSGi datasource factories



        try {
            unbindDataSources();
        } catch (NamingException e) {
            logger.log(BasicLevel.ERROR, "Cannot unbind datasources");
            throw new ServiceException("Cannot unbind datasources ", e);
        }

        if (jmxService != null) {
            unregisterDbmServiceMBean(getDomainName());
            unregisterJdbcResourceMBean(getDomainName(), getJonasServerName(), JDBC_RESOURCE_NAME);
        }

        // TODO We should remove the Model MBeans loaded by the JMX Service

        logger.log(BasicLevel.INFO, "DBM Service stopped");
    }

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

    /**
     * Creates a ConnectionManager (implementation of {@link DataSource}).
     * @param datasourceName datasource name
     * @param dsd a set of properties that describes a dataSource and the ConnectionPool
     */
    public void createDataSource(final String datasourceName, final 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 adjustperiod = dsd.getProperty(ADJUSTPERIOD, DEF_ADJUSTPERIOD).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(txService);

        // 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,
                         adjustperiod);

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

        // Admin code
        // Create and register JSR77 MBeans: JDBCDataSource and JDBCDriver
        String jdbcDataSourceName = datasourceName;
        String jdbcDriverName = "aJDBCDriver-" + jdbcDataSourceName; // TO BE IMPROVED
        String jdbcDriverClassName = className;
        String jdbcDataSourceON = registerJdbcDataSourceAndDriverMBean(getDomainName(),
                                                                       getJonasServerName(),
                                                                       jdbcDataSourceName,
                                                                       jdbcDriverName,
                                                                       jdbcDriverClassName,
                                                                       ds);
        // Updtae JDBCResource MBean
        jdbcResourceMBean.addJdbcDataSource(jdbcDataSourceON);
    }

    /**
     * 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 (ConnectionManager cm : cmList) {
                    cm.closeAllConnection();
                    dsn = cm.getDSName();
                    ictx.unbind(dsn);
                    boundDatasources.remove(dsn);
                }
            }
        } catch (NamingException e) {
            logger.log(BasicLevel.ERROR, "cannot unbind DataSources", e);
            throw e;
        }

        if (jmxService != null) {
            unregisterAllDataSourceAndDriverMBeans();
        }
    }

    /**
     * get ConnectionManager for the datasource having this JNDI name.
     */
    public ConnectionManager getConnectionManager(final String dsname) {
        if (cmList.size() > 0) {
            for (ConnectionManager cm : cmList) {
                if (cm.getDSName().equals(dsname)) {
                    return cm;
                }
            }
        }
        return null;
    }

    /**
     * return the list of the datasources.
     * @return
     */
    public Collection<ConnectionManager> 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 (ConnectionManager cm : cmList) {
                result += cm.getPool().getCurrentOpened();
            }
        }
        return new Integer(result);
    }

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

    /**
     * MBean method. Allows undeploy datasource.
     * @param name of the data source to unload
     */
    public void unloadDataSource(final String name) {
        logger.log(BasicLevel.DEBUG, "");
        try {
            if (cmList.size() > 0) {
                for (ConnectionManager cm : cmList) {
                    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);
                        // Admin code
                        String jdbcDataSourceOn = unregisterJdbcDataSourceAndDriverMBean(getDomainName(),
                                                                                         getJonasServerName(),
                                                                                         dsName);
                        // Update the list of dataSources in the JDBCResource MBean
                        jdbcResourceMBean.removeJdbcDataSource(jdbcDataSourceOn);
                    }
                    return;
                }
            }
        }  catch (Exception e) {
            logger.log(BasicLevel.ERROR, "Cannot unload DataSources", e);
        }
    }

    /**
     * MBean method. Return a datasource properties from a local file.
     * @param dsFile file name
     * @return datasource properties
     * @throws Exception could not read properties file
     */
    public Properties getDataSourcePropertiesFile(final 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(final String name,
                               final Properties prop,
                               final 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(final String jndiName) {
        return boundDatasources.get(jndiName);
    }

    // Admin code (JMX based)
    /**
     * Register DataBaseService MBean.
     * @param service dbm service to manage
     * @param domainName domain name
     */
    private void registerDbmServiceMBean(final Object service,
                                         final String domainName) {
        ObjectName on = JonasObjectName.databaseService(domainName);
        jmxService.registerMBean(service, on);
    }

    /**
     * Unregister DataBaseService MBean.
     * @param domainName domain name
     */
    private void unregisterDbmServiceMBean(final String domainName) {
        ObjectName on = JonasObjectName.databaseService(domainName);
        jmxService.unregisterMBean(on);
    }

    /**
     * Create and register JSR77 JDBCResource MBean.
     * @param domainName domain name
     * @param serverName server name
     * @param resourceName name of the JDBC Resource
     * @return The created MBean
     */
    private JDBCResource registerJdbcResourceMBean(final String domainName,
                                                   final String serverName,
                                                   final String resourceName) {
        JDBCResource jdbcResourceMBean = null;
        try {
            String jdbcResourceON = J2eeObjectName.JDBCResourceName(domainName,
                                                                    serverName,
                                                                    resourceName);
            jdbcResourceMBean = new JDBCResource(jdbcResourceON);
            jmxService.registerModelMBean(jdbcResourceMBean, jdbcResourceON);
        } catch (Exception e) {
            logger.log(BasicLevel.INFO, "DataBaseService: Cannot register JDBCResource MBean", e);
        }
        return jdbcResourceMBean;
    }

    /**
     * Create and register the JSR77 JDBCDataSource and JDBCDriver MBeans.
     * @param domainName domain name
     * @param serverName server name
     * @param jdbcDataSourceName name of the JDBC DataSource
     * @param jdbcDriverName name of the JDBC Driver
     * @param jdbcDriverClassName name of the JDBC Driver class
     * @param ds ConnectionManager object, the DataSource implementation in JOnAS
     * @return The OBJECT_NAME of the created MBean
     */
    private String registerJdbcDataSourceAndDriverMBean(final String domainName,
                                                        final String serverName,
                                                        final String jdbcDataSourceName,
                                                        final String jdbcDriverName,
                                                        final String jdbcDriverClassName,
                                                        final ConnectionManager ds) {
        JDBCDataSource jdbcDataSourceMBean = null;
        String jdbcDataSourceON = null;
        try {
            jdbcDataSourceON = J2eeObjectName.getJDBCDataSourceName(domainName,
                                                                    serverName,
                                                                    jdbcDataSourceName);
            jdbcDataSourceMBean = new JDBCDataSource(jdbcDataSourceON, ds);
            jmxService.registerModelMBean(jdbcDataSourceMBean, jdbcDataSourceON);
            if (logger.isLoggable(BasicLevel.DEBUG)) {
                logger.log(BasicLevel.DEBUG, "JDBCDataSource MBean created");
            }
        } catch (Exception e) {
            logger.log(BasicLevel.INFO, "DataBaseService: Cannot register JDBCDataSource MBean", e);
        }
        JDBCDriver jdbcDriverMBean = null;
        String jdbcDriverON = null;
        try {
            jdbcDriverON = J2eeObjectName.getJDBCDriverName(domainName,
                                                            serverName,
                                                            jdbcDriverName);
            jdbcDriverMBean = new JDBCDriver(jdbcDriverON);
            jdbcDriverMBean.setDriverClassName(jdbcDriverClassName);
            jmxService.registerModelMBean(jdbcDriverMBean, jdbcDriverON);
        } catch (Exception e) {
            logger.log(BasicLevel.INFO, "DataBaseService: Cannot register JDBCDriver MBean", e);
        }
        // Update the JDBC DataSource with the JDBC Driver
        jdbcDataSourceMBean.setJdbcDriver(jdbcDriverON);

        return jdbcDataSourceON;
    }

    /**
     * Unregister the JSR77 JDBCDataSource and JDBCDriver MBeans.
     * @param domainName domain name
     * @param serverName server name
     * @param jdbcDataSourceName name of the JDBC DataSource
     * @return OBJECT_NAME of the unregistered JDBCDataSource MBean
     */
    private String unregisterJdbcDataSourceAndDriverMBean(final String domainName,
                                                          final String serverName,
                                                          final String jdbcDataSourceName) {
        String jdbcDataSourceON = J2eeObjectName.getJDBCDataSourceName(domainName,
                                                                       serverName,
                                                                       jdbcDataSourceName);
        ObjectName onJDBCDataSource = null;
        String jdbcDriverName = null;
        ObjectName onJDBCDriver = null;
        MBeanServer mbeanServer = jmxService.getJmxServer();
        try {
            onJDBCDataSource = ObjectName.getInstance(jdbcDataSourceON);
            jdbcDriverName = (String) mbeanServer.getAttribute(onJDBCDataSource, "jdbcDriver");
            onJDBCDriver = ObjectName.getInstance(jdbcDriverName);
        } catch (Exception e) {
            logger.log(BasicLevel.INFO,
                       "DataBaseService: Cannot unregister MBean for datasource "
                       + jdbcDataSourceName, e);
        }
        // Unregister JDBCDataSource MBean
        jmxService.unregisterModelMBean(onJDBCDataSource);
        // Unregister JDBCDriver MBean
        jmxService.unregisterModelMBean(onJDBCDriver);
        return jdbcDataSourceON;
    }

    /**
     * Remove all JDBCDataSource and JDBCDriver MBeans contained in the JDBCResource.
     *
     */
    private void unregisterAllDataSourceAndDriverMBeans() {
        // Get JDBCDataSource OBJECT_NAMEs
        String[] ons = jdbcResourceMBean.getJdbcDataSources();
        ObjectName onJDBCDataSource = null;
        ObjectName onJDBCDriver = null;
        String dataSourceName = null;
        for (int i = 0; i < ons.length; i++) {
            try {
                onJDBCDataSource = ObjectName.getInstance(ons[i]);
            } catch (MalformedObjectNameException e) {
                logger.log(BasicLevel.INFO, "DataBaseService: Cannot unegister JDBCDataSource MBean", e);
                continue;
            }
            dataSourceName = onJDBCDataSource.getKeyProperty("name");
            MBeanServer mbeanServer = jmxService.getJmxServer();
            String jdbcDriverName = null;
            try {
                jdbcDriverName = (String) mbeanServer.getAttribute(onJDBCDataSource, "jdbcDriver");
            } catch (Exception e) {
                logger.log(BasicLevel.INFO,
                           "DataBaseService: Cannot unegister JDBCDriver MBean for datasource "
                           + dataSourceName, e);
                continue;
            }
            try {
                onJDBCDriver = new ObjectName(jdbcDriverName);
            } catch (MalformedObjectNameException e) {
                logger.log(BasicLevel.INFO, "DataBaseService: Cannot unegister JDBCDriver MBean" + dataSourceName, e);
                continue;
            }
            // Unregister JDBCDataSource MBean
            jmxService.unregisterModelMBean(onJDBCDataSource);
            // Unregister JDBCDriver MBean
            jmxService.unregisterModelMBean(onJDBCDriver);
            // Update the list of dataSources in the JDBCResource MBean
            jdbcResourceMBean.removeJdbcDataSource(onJDBCDataSource.toString());
        }
    }
    /**
     * Unregister JSR77 JDBCResource MBean.
     * @param domainName domain name
     * @param serverName server name
     * @param resourceName name of the JDBC Resource
     */
    private void unregisterJdbcResourceMBean(final String domainName,
                                             final String serverName,
                                             final String resourceName) {
        try {
            ObjectName jdbcResourceOn =
                J2eeObjectName.JDBCResource(domainName, serverName, resourceName);
            jmxService.unregisterModelMBean(jdbcResourceOn);
        } catch (Exception e) {
            logger.log(BasicLevel.INFO, "DataBaseService: Cannot unegister JDBCResource MBean", e);
        }
    }

    /**
     * @param txService the TransactionService to set
     */
    public void setTransactionService(final TransactionService txService) {
        this.txService = txService;
    }

    /**
     * @param jmxService the jmxService to set
     */
    public void setJmxService(final JmxService jmxService) {
        this.jmxService = jmxService;
    }

    /**
     * @param registry the registry servic to set
     */
    public void setRegistryService(final RegistryService registry) {
        this.registryService = registry;
    }

    /**
     * Returns the registry service.
     * @return The registry service
     */
    private RegistryService getRegistryService() {
        return registryService;
    }
}
