/*
 * JBoss, the OpenSource J2EE webOS
 * 
 * Distributable under LGPL license.
 * See terms of license at gnu.org.
 */
package org.jboss.cache.loader;

import com.mchange.v2.c3p0.DataSources;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Enumeration;
import java.util.Properties;

/**
 * Standalone connection factory based on c3p0 connection pooling library
 *
 * @author <a href="mailto:galder.zamarreno@jboss.com">Galder Zamarreno</a>
 */
public class C3p0ConnectionFactory extends NonManagedConnectionFactory
{
   private static final Log log = LogFactory.getLog(C3p0ConnectionFactory.class);
   private static final boolean trace = log.isTraceEnabled();

   private DataSource ds;

   @Override
   public void setConfig(AdjListJDBCCacheLoaderConfig config)
   {
      super.setConfig(config);

      Properties properties = config.getProperties();
      Enumeration e = properties.propertyNames();
      while (e.hasMoreElements())
      {
         String property = (String) e.nextElement();
         if (property.startsWith("c3p0."))
         {
            /* System properties should come before settings from XML configuration.

            For simplicity (c3p0 manual says overrides should not carry c3p0. start whereas system properties yes)
            and to avoid parsing, it's easier to set the values from XML configuration that should be c3p0. as
            system properties.

            So, this check allows us to determine if the System property was not set, in which case, we take the
            value from the XML configuration and set it to be a System property. If the value from the XML config
            was already set as System property, we do nothing, original System property should stand. */

            String xmlPropertyValue = properties.getProperty(property);
            String sysPropertyValue = System.getProperty(property);
            if (System.getProperty(property) == null)
            {
               System.setProperty(property, xmlPropertyValue);
               if (log.isDebugEnabled())
               {
                  log.debug("c3p0 property defined in XML: " + property + "=" + xmlPropertyValue);
               }
            }
            else
            {
               if (log.isDebugEnabled())
               {
                  log.debug(property + "=" + sysPropertyValue + " defined as system property. It will override the value defined in XML which was: " + xmlPropertyValue);
               }
            }
         }
      }
   }

   @Override
   public void start() throws Exception
   {
      /* We need to call super so that the driver is loaded. This is required by the C3P0 manual. */
      super.start();

      DataSource unpooled = DataSources.unpooledDataSource(getUrl(), getUsr(), getPwd());
      ds = DataSources.pooledDataSource(unpooled);

      if (log.isDebugEnabled())
      {
         log.debug("Pooled datasource(url=" + getUrl() + ",usr=" + getUsr() + ",pwd=" + getPwd() + ") started.");
      }
   }

   @Override
   public Connection checkoutConnection() throws SQLException
   {
      Connection connection = ds.getConnection();
      if (trace)
      {
         log.trace("Connection checked out: " + connection);
      }
      return connection;
   }

   @Override
   public void stop()
   {
      try
      {
         DataSources.destroy(ds);
         if (log.isDebugEnabled())
         {
            log.debug("Pooled datasource destroyed.");
         }
      }
      catch (SQLException sqle)
      {
         log.warn("Could not destroy C3P0 connection pool: " + ds, sqle);
      }
   }

   protected DataSource getDataSource()
   {
      return ds;
   }
}
