
// Copyright (c) 1999, 2000 Oracle Corporation
package oracle.jbo.common.ampool;

import java.util.Hashtable;
import java.util.Enumeration;
import java.util.Properties;

import oracle.jbo.common.Configuration;
import oracle.jbo.common.PropertyConstants;

/**
 **  This class manages the Application Pool. It is a singleton instance.
 ** <BR>
 ** <a HREF="PoolMgr.txt">View implementation of PoolMgr</a>
 ** <P>
 ** @author Juan Oropeza
 **/
public class PoolMgr extends Object
{
  static PoolMgr instance = new PoolMgr();
  Hashtable poolList = new Hashtable(10);

  /**
  ** Constructor
  **/
  private PoolMgr()
  {
  }

  /**
  **  Retrieves the singleton instance of the Pool Manager
  **/
  static public PoolMgr getInstance()
  {
    return instance;
  }

  /**
  **  Returns true if the pool has already been created.
  **/
  public synchronized boolean isPoolCreated(String sName)
  {
    if(poolList.get(sName) != null)
      return true;

    return false;
  }

  /**
  **  Returns the ApplicationPool interface for the named pool.
  **/
  public synchronized ApplicationPool getPool(String sName)
  {
    return (ApplicationPool)poolList.get(sName);
  }

  /**
  **  Removes the named pool and calls remove() method on all ApplicationModule
  **  instances that are being managed by the pool.
  ** @param the name of the pool to remove.
  **/
  public synchronized void removePool(String sName)
  {
    if(!isPoolCreated(sName))
      return;

    ApplicationPool pool = getPool(sName);

    poolList.remove(sName);

    pool.releaseInstances();
  }

  /**
  **  Create a new Application Module pool, throws an exception if the pool is already registered.
  **  The connectInfo parameter provides the necessary settings required for creating instances of
  **  Application Modules that are part of the pool. You can also specify the name of the class that
  **  implements the ApplicationPool interface. This is an important setting for users that want to provide
  **  a custom implementation of the ApplicationPool interface. The default ApplicationPool implementation is
  **  in the oracle.jbo.client.ampool.ApplicationPoolImpl class.
  **/
  public synchronized ApplicationPool createPool(String sName , String sClass, String sApplicationModule, String sConnectString, Hashtable env) throws Exception
  {
      if (isPoolCreated(sName))
      {
         throw new ApplicationPoolException(AMPoolMessageBundle.class,
                                            AMPoolMessageBundle.EXC_AMPOOL_MGR_ALREADY_CREATED,
                                            new Object[] { sName });
      }

      Class  poolClass = Class.forName(sClass);

      ApplicationPool pool = (ApplicationPool)poolClass.newInstance();

      pool.initialize(sName, sApplicationModule, sConnectString, env);

      poolList.put(sName, pool);

      return pool;
  }


   /**
  **  Create a new Application Module pool, throws an exception if the pool is already registered.
  **  The connectInfo parameter provides the necessary settings required for creating instances of
  **  Application Modules that are part of the pool. You can also specify the name of the class that
  **  implements the ApplicationPool interface. This is an important setting for users that want to provide
  **  a custom implementation of the ApplicationPool interface. The default ApplicationPool implementation is
  **  in the oracle.jbo.client.ampool.ApplicationPoolImpl class.
  **/
  public synchronized ApplicationPool createPool(String sName , String sApplicationModule, String sConnectString, Hashtable env) throws Exception
  {
      return createPool(sName , "oracle.jbo.common.ampool.ApplicationPoolImpl", sApplicationModule, sConnectString, env);
  }

  /**
  **  Returns the Enumeration interface that allows you to enumerate through
  **  all the Application Pools that are registered with the Pool Manager.
  **/
  public synchronized Enumeration getPools()
  {
    return poolList.elements();
  }

  public synchronized Enumeration getPoolNames()
  {
    return poolList.keys();
  }

  /**
  **  Creates a new Application Module pool, throws an exception if the pool is
  **  already registered.
  ** <p>
  **  This method creates an Application Module pool, based on the named
  **  AppModule Configuaraion
  **
  ** <p>
  **  The application module configuration provides the necessary settings
  **  required for creating instances of Application Modules that are part of
  **  the pool. You can also specify the name of a custom application pool
  **  implementation (implements oracle.jbo.common.ApplicationPool interface).
  **  The default ApplicationPool implementation is provided in
  **  oracle.jbo.common.ampool.ApplicationPoolImpl.
  **
  **  @param sName name of the pool
  **  @param sPackageName package name of the AppModule., package10, for package10.Package10Module
  **  @param sConfigName  named Configuration to use
  **  @param props collection of additional properties to be passed to the application pool
  **/
  public synchronized ApplicationPool createPool(String sName , String sPackageName, String sConfigName, Properties props)
                    throws Exception
  {
      Configuration configuration = new Configuration();
      configuration.loadFromClassPath(Configuration.buildConfigurationFileNameFromClassPath(sPackageName));
      Hashtable config = configuration.getConfiguration(sConfigName);
      String sApplicationModule = null;
      sApplicationModule = (String)config.get(Configuration.APPLICATION_NAME_PROPERTY);
      String sConnectString  = (String)config.get(Configuration.DB_CONNECTION_PROPERTY);

      if ((sApplicationModule == null) || (sConnectString == null))
         throw new Exception("Configuration does not define one or more properties ");


      // If properties were passed to createPool then merge them with the
      // config properties
      if (props != null)
      {
         Enumeration propKeys = props.keys();
         Object key = null;
         String keyStr = null;
         boolean doMapProperty = true;

         while (propKeys.hasMoreElements())
         {
            // By default merge the specified properties into the
            // configuration properties
            doMapProperty = true;

            key = propKeys.nextElement();

            // Check for special cases
            if (key instanceof String)
            {
               keyStr = (String)key;

               if (keyStr.equals(PropertyConstants.IS_STATELESS_RUNTIME))
               {
                  // Check if a release mode has already been mapped.
                  // If so, ignore the property and use the configuration value
                  // instead.
                  if (config.containsKey(PropertyConstants.AM_RELEASE_MODE))
                  {
                     doMapProperty = false;
                  }
               }
            }

            if (doMapProperty)
            {
               config.put(key, props.get(key));
            }
         }
      }

/* Why do we do that here? <Charles>
       // dump the environment
       Enumeration e = env.keys();
       String sValue;
       String sKey;

       while(e.hasMoreElements())
       {
         sKey = e.nextElement().toString();
         sValue = env.get(sKey).toString();
       }
*/
       //


       // Check for a pool class name property in the config.  If it exists use
       // the pool class name to create the pool.  Otherwise use the default
       // pool implementation.
       String poolClassName = (String)config.get(PropertyConstants.ENV_POOL_CLASS_NAME);
       ApplicationPool pool = null;
       if (poolClassName != null)
       {
         pool = createPool(sName, poolClassName, sApplicationModule, sConnectString, config);
       }
       else
       {
         pool = createPool(sName, sApplicationModule, sConnectString, config);
       }

       pool.setUserData(config);

       return pool;
  }



}
