/*
 * @(#)JSPApplicationRegistry.java
 *
 * Copyright 1999-2002 by Oracle Corporation,
 * 500 Oracle Parkway, Redwood Shores, California, 94065, U.S.A.
 * All rights reserved.
 *
 * This software is the confidential and proprietary information
 * of Oracle Corporation.
 */

package oracle.jbo.html.jsp;

import java.io.InputStream;
import java.util.Hashtable;
import java.util.Properties;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.servlet.jsp.PageContext;
import oracle.jbo.ApplicationModule;
import oracle.jbo.common.Diagnostic;
import oracle.jbo.common.JBOClass;
import oracle.jbo.common.PropertyConstants;
import oracle.jbo.common.PropertyMetadata;
import oracle.jbo.common.ampool.ApplicationPool;
import oracle.jbo.common.ampool.PoolMgr;
import oracle.jbo.common.ampool.SessionCookie;
import oracle.jbo.common.ampool.SessionCookieFactory;
import oracle.jbo.html.HtmlServices;
import oracle.jbo.http.HttpContainer;
import oracle.jbo.http.HttpSessionCookieFactory;
import oracle.jbo.http.HttpSessionCookieHelper;
import oracle.jbo.http.HttpSessionCookieHelperManager;
import oracle.jdeveloper.html.WebBeanImpl;

/**
 **  This class provides the main interface for DataWebBeans to use the Application Module Pool.
 **
 ** <a HREF="JSPApplicationRegistry.txt">View implementation of JSPApplicationRegistry</a>
 **
 ** @author  Juan Oropeza
 ** @version PUBLIC
 **
 **/
public class JSPApplicationRegistry extends WebBeanImpl
{
   static JSPApplicationRegistry mInstance =  new JSPApplicationRegistry();

   static PoolMgr mPoolManager = PoolMgr.getInstance();

   private static final String TIMEOUT_HANDLER_SUFFIX = "_TimeoutHandler";

   public static final String RESERVED                = PropertyConstants.AM_RELEASE_RESERVED;
   public static final String STATEFUL                = PropertyConstants.AM_RELEASE_STATEFUL;
   public static final String STATELESS               = PropertyConstants.AM_RELEASE_STATELESS;

   private static final String SESSION_INITIALIZED = "SessionInitialized";
   private static Hashtable mLoadedProperties = new Hashtable();

   /**
   **  Constructor, this should not be called directly
   **/
   public JSPApplicationRegistry()
   {
   }

   /**
   **  Returns the singleton instance of the registry class.
   **/
   static public  JSPApplicationRegistry getInstance()
   {
      return mInstance;
   }

   /**
   **  Returns the user data associated with the named pool. The user data is a convenient palce for storing
   **  and retrieving application-specific information shared by all application instances that are part of the
   **  named pool.
   **/
   static synchronized public Hashtable getAppSettings(String poolName)
   {
      ApplicationPool pool = mPoolManager.getPool(poolName);

      return (Hashtable)pool.getUserData();
   }

   /**
    * Release the specified application module instance.  This method is
    * intended for use by servlet clients in order to release an application
    * module resource to the application module pool.</p>
    * <p>
    * The specified release mode will determine how the application module is
    * returned to the pool.  The following release modes are currently
    * supported:</p>
    * <p>
    * <b>RESERVED:  </b>Do not allow the application module instance to be
    *    shared with other client requests.  The reserved lock will be released
    *    when the application module is checked in by a latter request in the
    *    application life cycle or when the http session times out.</p>
    * <p>
    * <b>STATEFUL:  </b>Only available if a HttpServletResponse has been
    *    specified. The implementation will check the application module
    *    instance into the pool in a stateful manner which will allow the pool
    *    to maintain the application module state between session requests.
    *    This may involve passivating the session's application module state so
    *    that the application may be reused by other session requests.  Using
    *    this option will cause a servlet cookie to be generated and written
    *    to the HttpServletResponse.</p>
    * <p>
    * <b>STATELESS:  </b>Check the application module instance into the pool
    *    without retaining application module state.</p>
    *
    * @see oracle.jbo.common.ampool.ApplicationPool ApplicationPool
    *
    * @deprecated application developers should use the following sample
    * to release an ApplicationModule instead of releaseAppModuleInstance
    * (assumes that the ApplicationModule instance was acquired with a
    * SessionCookie, see getAppModuleInstance for more information):
    * <p>
    * <tt>
    *  HttpContainer container = HttpContainer.getInstanceFromSession(session);
    *
    *  SessionCookie cookie = container.getSessionCookies(applicationId);
    *
    *  // only release the ApplicationModule if it was reserved
    *  if (cookie != null && cookie.isApplicationModuleReserved())
    *  {
    *     if (<Reserved release mode>)
    *     {
    *        cookie.releaseApplicationModule(
    *           SessionCookie.UNSHARED
    *           , SessionCookie.STATE_UNMANAGED);
    *     }
    *     else if (<Stateful release mode>)
    *     {
    *        cookie.releaseApplicationModule(
    *           SessionCookie.SHARED
    *           , SessionCookie.STATE_MANAGED);
    *     }
    *     else if (<Stateless release mode>)
    *     {
    *        cookie.releaseApplicationModule(
    *           SessionCookie.SHARED
    *           , SessionCookie.STATE_UNMANAGED);
    *     }
    *  }
    * </tt>
    * @since 5.0
    * @see oracle.jbo.http.HttpContainer
    * @see oracle.jbo.http.HttpSessionCookie
    */
   public void releaseAppModuleInstance(
      String applicationId
      , ApplicationModule appModule
      , ApplicationPool pool
      , HttpSession session
      , HttpServletResponse response
      , String releaseMode)
   {
      // Only proceed if the application is not available.  Otherwise,
      // the application module has been successfully checked in already.
      // This check is necessary to prevent redundant check-ins to the pool.
      // The check is implemented here because the JSPApplicationRegistry
      // may potentially register two application module references in the
      // HTTP contexts (page and session).
      if (pool == null || !pool.isAvailable(appModule))
      {
         releaseAppModuleInstance(applicationId, session, response, releaseMode);
      }
   }

   /**
    * @deprecated application developers should use the following sample
    * to release an ApplicationModule instead of releaseAppModuleInstance
    * (assumes that the ApplicationModule instance was acquired with a
    * SessionCookie, see getAppModuleInstance for more information):
    * <p>
    * <tt>
    *  HttpContainer container = HttpContainer.getInstanceFromSession(session);
    *
    *  SessionCookie cookie = container.getSessionCookies(applicationId);
    *
    *  // only release the ApplicationModule if it was reserved
    *  if (cookie != null && cookie.isApplicationModuleReserved())
    *  {
    *     if (<Reserved release mode>)
    *     {
    *        cookie.releaseApplicationModule(
    *           SessionCookie.UNSHARED
    *           , SessionCookie.STATE_UNMANAGED);
    *     }
    *     else if (<Stateful release mode>)
    *     {
    *        cookie.releaseApplicationModule(
    *           SessionCookie.SHARED
    *           , SessionCookie.STATE_MANAGED);
    *     }
    *     else if (<Stateless release mode>)
    *     {
    *        cookie.releaseApplicationModule(
    *           SessionCookie.SHARED
    *           , SessionCookie.STATE_UNMANAGED);
    *     }
    *  }
    * </tt>
    * @since 5.0
    * @see oracle.jbo.http.HttpContainer
    * @see oracle.jbo.http.HttpSessionCookie
    */
   public void releaseAppModuleInstance(
      String applicationId
      , HttpSession session
      , HttpServletResponse response
      , String releaseMode)
   {
      HttpContainer container = HttpContainer.getInstanceFromSession(session);
      SessionCookie cookie = container.getSessionCookie(applicationId);

      // If the application release mode has been specified as reserved
      // then promote the application module to the session level context.
      // The application module will be checked in if it is used in a page
      // again with a release mode other than reserved or if the session
      // times out.
      if (JSPApplicationRegistry.RESERVED.equals(releaseMode))
      {
         Diagnostic.println("ApplicationModule release mode is:  Reserved");
         cookie.releaseApplicationModule(
            false // checkin
            , true); // manageState
      }
      // If a stateful release mode has been specified then passivate
      // the application module and return it to the application pool.  This
      // mode is not supported if a response object has not been specified.
      else if ((response != null)
         && (JSPApplicationRegistry.STATEFUL.equals(releaseMode)))
      {

         Diagnostic.println("ApplicationModule release mode is:  Stateful");

         cookie.releaseApplicationModule(
            true // checkin
            , true); // manageState
         cookie.writeValue(response);
      }
      // If the release mode is stateless then simply return the application
      // module to the pool.
      else
      {
         Diagnostic.println("ApplicationModule release mode is:  Stateless");

         cookie.releaseApplicationModule(
            true // checkin
            , false); // manageState
         cookie.writeValue(response);
      }
   }


   /**
    * @see #public void releaseAppModuleInstance(String, ApplicationModule, ApplicationPool, HttpSession, HttpServletResponse, String releaseMode)
    *
    * @deprecated application developers should use the following sample
    * to release an ApplicationModule instead of releaseAppModuleInstance
    * (assumes that the ApplicationModule instance was acquired with a
    * SessionCookie, see getAppModuleInstance for more information):
    * <p>
    * <tt>
    *  HttpContainer container = HttpContainer.getInstanceFromSession(session);
    *
    *  SessionCookie cookie = container.getSessionCookies(applicationId);
    *
    *  // only release the ApplicationModule if it was reserved
    *  if (cookie != null && cookie.isApplicationModuleReserved())
    *  {
    *     if (<Reserved release mode>)
    *     {
    *        cookie.releaseApplicationModule(
    *           SessionCookie.UNSHARED
    *           , SessionCookie.STATE_UNMANAGED);
    *     }
    *     else if (<Stateful release mode>)
    *     {
    *        cookie.releaseApplicationModule(
    *           SessionCookie.SHARED
    *           , SessionCookie.STATE_MANAGED);
    *     }
    *     else if (<Stateless release mode>)
    *     {
    *        cookie.releaseApplicationModule(
    *           SessionCookie.SHARED
    *           , SessionCookie.STATE_UNMANAGED);
    *     }
    *  }
    * </tt>
    * @since 5.0
    * @see oracle.jbo.http.HttpContainer
    * @see oracle.jbo.http.HttpSessionCookie
    */
   public void releaseAppModuleInstance(
      ApplicationModule appModule
      , ApplicationPool pool
      , HttpSession session
      , HttpServletResponse response
      , String releaseMode)
   {
      String applicationId = (String)session.getValue(appModule.toString());
      releaseAppModuleInstance(applicationId, session, response, releaseMode);
   }

   /**
    * @see #public void releaseAppModuleInstance(String, ApplicationModule, ApplicationPool, HttpSession, HttpServletResponse, String releaseMode)
    *
    * @deprecated application developers should use the following sample
    * to release an ApplicationModule instead of releaseAppModuleInstance
    * (assumes that the ApplicationModule instance was acquired with a
    * SessionCookie, see getAppModuleInstance for more information):
    * <p>
    * <tt>
    *  HttpContainer container = HttpContainer.getInstanceFromSession(session);
    *
    *  SessionCookie cookie = container.getSessionCookies(applicationId);
    *
    *  // only release the ApplicationModule if it was reserved
    *  if (cookie != null && cookie.isApplicationModuleReserved())
    *  {
    *     if (<Reserved release mode>)
    *     {
    *        cookie.releaseApplicationModule(
    *           SessionCookie.UNSHARED
    *           , SessionCookie.STATE_UNMANAGED);
    *     }
    *     else if (<Stateful release mode>)
    *     {
    *        cookie.releaseApplicationModule(
    *           SessionCookie.SHARED
    *           , SessionCookie.STATE_MANAGED);
    *     }
    *     else if (<Stateless release mode>)
    *     {
    *        cookie.releaseApplicationModule(
    *           SessionCookie.SHARED
    *           , SessionCookie.STATE_UNMANAGED);
    *     }
    *  }
    * </tt>
    * @since 5.0
    * @see oracle.jbo.http.HttpContainer
    * @see oracle.jbo.http.HttpSessionCookie
    */
   public void releaseAppModuleInstance(
      ApplicationModule appModule
      , ApplicationPool pool
      , PageContext pageContext
      , String releaseMode)
   {
      HttpSession session = pageContext.getSession();

      String applicationId = (String)session.getValue(appModule.toString());
      HttpServletResponse response = (HttpServletResponse)pageContext.getResponse();

      releaseAppModuleInstance(applicationId, session, response, releaseMode);
   }

   /**
    * Get an application module instance for the specified application pool.
    * This method is intended for servlet clients that require an application
    * module.
    * <p>
    * The implementation will attempt to locate an application module in the
    * session context before asking the application pool for an application
    * module.
    * <p>
    * If an application module is not found in the session or page contexts
    * the implementation will check the http request for a session cookie value.
    * If a session cookie value exists the method will instantiate a new
    * (@link oracle.jbo.common.ampool.SessionCookie SessionCookie} instance
    * using that cookie value.  If a session cookie value is not found in the
    * request then the method will invoke (@link #getSessionId getSessionId}.
    * to obtain a unique session identifier.  The returned session id will be
    * used to instantiate a new
    * (@link oracle.jbo.common.ampool.SessionCookie SessionCookie} instance.
    * <p>
    * The SessionCookie instance generated above is passed to the application
    * pool during checkout.  The application pool will use the session cookie
    * to identify the client session and to activate any application state
    * which may have been passivated at the end of a previous request from this
    * session.
    * <p>
    * @param applicationId the id of the requesting session application
    *   The applicationId should match the name of the pool that was used to
    *   generate the requested instance
    *
    * @see oracle.jdeveloper.html.DataWebBeanImpl#internalInitialize()
    *
    * @deprecated application developers should use the following sample
    * to acquire an ApplicationModule instead of getAppModuleInstance:
    * <p>
    * <tt>
    *      // Load the pool creation properties with the name of our custom
    *   // application pool class.
    *   Properties cookieProps = new Properties();
    *   cookieProps.put(HttpSessionCookieFactory.HTTP_SERVLET_REQUEST, request);
    *
    *   // Find a session cookie in the HttpSession for the specified 
    *   // application id.  If one does not exist this method will create one.
    *   SessionCookie cookie = HttpContainer.findSessionCookie(
    *      session
    *      , applicationId
    *      , configName // poolName
    *      , configPackage
    *      , configName
    *      , null // pool properties
    *      , cookieProps);
    *
    *   ApplicationModule appModule = cookie.useApplicationModule();
    * </tt>
    * <p>
    * where configPackage is the fully qualified package name of the
    * ApplicationModule.
    * <p>
    * For more information please see the pooling sample at
    * "$JDEV_HOME/BC4J/samples/Pooling".
    * <p>
    * @since 5.0
    * @see oracle.jbo.http.HttpContainer
    * @see oracle.jbo.http.HttpSessionCookie
    */
   public ApplicationModule getAppModuleInstance(
      String applicationId
      , HttpServletRequest request
      , HttpSession session)
   {
      return getAppModuleInstance(
               applicationId    // applicationId
               , applicationId    // poolId
               , null
               , request
               , null // response
               , session);
   }

   /**
    *
    * @deprecated application developers should use the following sample
    * to acquire an ApplicationModule instead of getAppModuleInstance:
    * <p>
    * <tt>
    *      // Load the pool creation properties with the name of our custom
    *   // application pool class.
    *   Properties cookieProps = new Properties();
    *   cookieProps.put(HttpSessionCookieFactory.HTTP_SERVLET_REQUEST, request);
    *
    *   // Find a session cookie in the HttpSession for the specified
    *   // application id.  If one does not exist this method will create one.
    *   SessionCookie cookie = HttpContainer.findSessionCookie(
    *      session
    *      , applicationId
    *      , configName // poolName
    *      , configPackage
    *      , configName
    *      , null // pool properties
    *      , cookieProps);
    *
    *   ApplicationModule appModule = cookie.useApplicationModule();
    * </tt>
    * <p>
    * where configPackage is the fully qualified package name of the
    * ApplicationModule.
    * <p>
    * For more information please see the pooling sample at
    * "$JDEV_HOME/BC4J/samples/Pooling".
    * <p>
    * @since 5.0
    * @see oracle.jbo.http.HttpContainer
    * @see oracle.jbo.http.HttpSessionCookie
    */
   public ApplicationModule getAppModuleInstance(
      String applicationId
      , HttpServletRequest request
      , HttpServletResponse response
      , HttpSession session)
   {
      return getAppModuleInstance(
               applicationId    // applicationId
               , applicationId    // poolId
               , null
               , request
               , response
               , session);
   }

   /**
    * @see #getAppModuleInstance(String, HttpServletRequest, HttpSession)
    *
    *
    * @deprecated application developers should use the following sample
    * to acquire an ApplicationModule instead of getAppModuleInstance:
    * <p>
    * <tt>
    *      // Load the pool creation properties with the name of our custom
    *   // application pool class.
    *   Properties cookieProps = new Properties();
    *   cookieProps.put(HttpSessionCookieFactory.HTTP_SERVLET_REQUEST, request);
    *
    *   // Find a session cookie in the HttpSession for the specified
    *   // application id.  If one does not exist this method will create one.
    *   SessionCookie cookie = HttpContainer.findSessionCookie(
    *      session
    *      , applicationId
    *      , configName // poolName
    *      , configPackage
    *      , configName
    *      , null // pool properties
    *      , cookieProps);
    *
    *   ApplicationModule appModule = cookie.useApplicationModule();
    * </tt>
    * <p>
    * where configPackage is the fully qualified package name of the
    * ApplicationModule.
    * <p>
    * For more information please see the pooling sample at
    * "$JDEV_HOME/BC4J/samples/Pooling".
    * <p>
    * @since 5.0
    * @see oracle.jbo.http.HttpContainer
    * @see oracle.jbo.http.HttpSessionCookie
    */
   public ApplicationModule getAppModuleInstance(
      String      applicationId,
      PageContext pageContext)
   {
      return getAppModuleInstance(
               applicationId    // applicationId
               , applicationId    // poolId
               , pageContext
               , (HttpServletRequest) pageContext.getRequest()
               , (HttpServletResponse) pageContext.getResponse()
               , pageContext.getSession());
   }

   /**
    * @see #getAppModuleInstance(String, HttpServletRequest, HttpSession)
    *
    *
    * @deprecated application developers should use the following sample
    * to acquire an ApplicationModule instead of getAppModuleInstance:
    * <p>
    * <tt>
    *      // Load the pool creation properties with the name of our custom
    *   // application pool class.
    *   Properties cookieProps = new Properties();
    *   cookieProps.put(HttpSessionCookieFactory.HTTP_SERVLET_REQUEST, request);
    *
    *   // Find a session cookie in the HttpSession for the specified
    *   // application id.  If one does not exist this method will create one.
    *   SessionCookie cookie = HttpContainer.findSessionCookie(
    *      session
    *      , applicationId
    *      , configName // poolName
    *      , configPackage
    *      , configName
    *      , null // pool properties
    *      , cookieProps);
    *
    *   ApplicationModule appModule = cookie.useApplicationModule();
    * </tt>
    * <p>
    * where configPackage is the fully qualified package name of the
    * ApplicationModule.
    * <p>
    * For more information please see the pooling sample at
    * "$JDEV_HOME/BC4J/samples/Pooling".
    * <p>
    * @since 5.0
    * @see oracle.jbo.http.HttpContainer
    * @see oracle.jbo.http.HttpSessionCookie
    */
   public ApplicationModule getAppModuleInstance(
      String      applicationId,
      String      poolName,
      PageContext pageContext)
   {
      return getAppModuleInstance(
               applicationId
               , poolName
               , pageContext
               , (HttpServletRequest) pageContext.getRequest()
               , (HttpServletResponse) pageContext.getResponse()
               , pageContext.getSession());
   }

   /**
    * This is the where all the getAppModuleInstance comes to
    */
   private ApplicationModule getAppModuleInstance(
      String                 applicationId
      , String               poolName
      , PageContext          pageContext
      , HttpServletRequest   request
      , HttpServletResponse  response
      , HttpSession          session
      )
   {
      ApplicationModule appModule = null;

      Properties cookieProps = new Properties();
      cookieProps.put(HttpSessionCookieFactory.HTTP_SERVLET_REQUEST, request);

      SessionCookie cookie = HttpContainer.findSessionCookie(
         session
         , applicationId
         , poolName
         , (String)null
         , (String)null
         , null
         , cookieProps);

      appModule = cookie.useApplicationModule();

      // Temporary fix.  Necessary so that the datawebbeans may determine
      // the applicationId of an application module instance.  Redundant.
      request.getSession(true).putValue(appModule.toString(), applicationId);

      // Place the appModule in the pageContext for backwards compatibility
      // purposes.  We should not access this value internally.
      if (pageContext != null)
      {
         addAppModuleToPageContext(applicationId, appModule, pageContext);
      }

      return appModule;
   }

   /**
    * Check the relevant http contexts for the named application module
    * instance.
    * <p>
    * If the page context is not null then first check the page context
    * for a Bc4jPageContext container.  If one is found then check for
    * the specified application module instance.  Otherwise check if the
    * specified application module instance has been placed in the session
    * context.</p>
    *
    * @param applicationId the application module id of the requested 
    * application module
    *   The applicationId should match the name of the pool that was used to
    *   generate the requested instance
    * @param session the HttpSession context that should be checked for the
    *    named application module instance
    * @param pageContext if a JSP client the name of the pageContext that
    *    should be checked for the named application module instance.  Null
    *    otherwise.
    *
    * @deprecated application developers should use the following sample
    * to acquire an ApplicationModule instead of getAppModuleFromContexts 
    * (assumes that the ApplicationModule instance was acquired with a
    * SessionCookie, see getAppModuleInstance for more information):
    * <p>
    * <tt>
    *  HttpContainer container = HttpContainer.getInstanceFromSession(session);
    *
    *  SessionCookie cookie = container.getSessionCookies(applicationId);
    *  ApplicationModule am = cookie.useApplicationModule();
    * </tt>
    * <p>
    * where the applicationId is the id that was used when the SessionCookie
    * was created (see getAppModuleInstance).
    * <p>
    * @since 5.0
    * @see oracle.jbo.http.HttpContainer
    * @see oracle.jbo.http.HttpSessionCookie
    */
   public ApplicationModule getAppModuleFromContexts(
      String applicationId
      , HttpSession session
      , PageContext pageContext)
   {
      ApplicationModule appModule = null;

      // Correction logic to handle a null session parameter.
      HttpSession httpSession = (session == null ? pageContext.getSession() : session);
      synchronized(httpSession)
      {
         appModule =
            getAppModuleFromPageContext(applicationId, applicationId, pageContext);

         // If the appModule was not located in the page context
         if (appModule == null)
         {
            appModule = getAppModuleFromSession(applicationId, session);
         }
      }

      return appModule;
   }

   /**
    * Check the http session for the named application module
    * instance.
    *
    * @param applicationId the id of the requested application module instance
    *   The applicationId should match the name of the pool that was used to generate
    *   the requested instance
    * @param session the HttpSession context that should be checked for the
    *    named application module instance
    *
    *
    * @deprecated application developers should use the following sample
    * to acquire an ApplicationModule instead of getAppModuleFromContexts
    * (assumes that the ApplicationModule instance was acquired with a
    * SessionCookie, see getAppModuleInstance for more information):
    * <p>
    * <tt>
    *  HttpContainer container = HttpContainer.getInstanceFromSession(session);
    *
    *  SessionCookie cookie = container.getSessionCookies(applicationId);
    *  ApplicationModule am = cookie.useApplicationModule();
    * </tt>
    * <p>
    * where the applicationId is the id that was used when the SessionCookie
    * was created (see getAppModuleInstance).
    * <p>
    * @since 5.0
    * @see oracle.jbo.http.HttpContainer
    * @see oracle.jbo.http.HttpSessionCookie
    */
   public ApplicationModule getAppModuleFromSession(
      String applicationId,
      HttpSession session)
   {
      return getAppModuleFromSession(applicationId, applicationId, session);
   }

   /**
    * Check the http session for the named application module
    * instance.
    *
    * @param applicationId the id of the requested application module instance
    * @param poolName the application name of the requesting thread
    * @param session the HttpSession context that should be checked for the
    *    named application module instance
    *
    *
    * @deprecated application developers should use the following sample
    * to acquire an ApplicationModule instead of getAppModuleFromContexts
    * (assumes that the ApplicationModule instance was acquired with a
    * SessionCookie, see getAppModuleInstance for more information):
    * <p>
    * <tt>
    *  HttpContainer container = HttpContainer.getInstanceFromSession(session);
    *
    *  SessionCookie cookie = container.getSessionCookies(applicationId);
    *  ApplicationModule am = cookie.useApplicationModule();
    * </tt>
    * <p>
    * where the applicationId is the id that was used when the SessionCookie
    * was created (see getAppModuleInstance).
    * <p>
    * @since 5.0
    * @see oracle.jbo.http.HttpContainer
    * @see oracle.jbo.http.HttpSessionCookie
    */
   public ApplicationModule getAppModuleFromSession(
      String applicationId
      , String poolName
      , HttpSession session)
   {
      ApplicationModule appModule = null;

      HttpContainer container = HttpContainer.getInstanceFromSession(session);
      SessionCookie cookie = container.getSessionCookie(applicationId);
      appModule = cookie.useApplicationModule(false); // lock

      return appModule;
   }

   private ApplicationModule getAppModuleFromPageContext(String applicationId, String poolName, PageContext pageContext)
   {
      ApplicationModule appModule = null;

      if (pageContext != null)
      {
         // Use getAttribute instead of findAttribute.  findAttribute will locate
         // the container in the session context if not located in the pageContext.
         HttpContainer container = (HttpContainer)pageContext.getAttribute(HttpContainer.PAGE_CONTEXT_CONTAINER_NAME, PageContext.REQUEST_SCOPE);

         if (container == null)
         {
            container = new HttpContainer(pageContext);

            pageContext.setAttribute(HttpContainer.PAGE_CONTEXT_CONTAINER_NAME, container, PageContext.REQUEST_SCOPE);
         }

         appModule = (ApplicationModule)container.getValue(HttpContainer.APPLICATION_PREFIX + applicationId);
      }

      return appModule;
   }

    /**
    **  Convenience method for defining a new application pool from a property file. This also transfers some system
    **  specific variables to the JSP Session object.
    **/
   static public void registerApplicationFromPropertyFile(HttpSession session, String sPropFileName)
   {
      registerApplicationFromPropertyFile(sPropFileName);

      synchronized(session)
      {
         if (!PropertyConstants.TRUE.equals((String)session.getValue(SESSION_INITIALIZED)))
         {
            Hashtable   settings = getAppSettings(sPropFileName);
            int         nTimeOut = 300;

            if (settings != null)
            {
               // see if we have a setting for the session timeout
               String sTimeOut;


               if(settings.get("HttpSessionTimeOut") != null)
               {
                 sTimeOut = (String)settings.get("HttpSessionTimeOut");

                 if(sTimeOut != null)
                 {
                   nTimeOut = Integer.parseInt(sTimeOut);
                 }
               }

               if(settings.get("ImageBase") != null)
               {
                  session.putValue("ImageBase", settings.get("ImageBase"));
               }
               else
               {
                  settings.put("ImageBase", "/webapp/images");
                  session.putValue("ImageBase", "/webapp/images");
               }

               if(settings.get("CSSURL") != null)
               {
                  session.putValue("CSSURL",settings.get("CSSURL"));
               }
               else
               {
                  settings.put("CSSURL", "/webapp/css/oracle.css");
                  session.putValue("CSSURL", "/webapp/css/oracle.css");
               }
            }

            // place default renderers into session, these will not be
            // exposed via config file
            HtmlServices.registerORDrenderer(session);

            session.putValue(SESSION_INITIALIZED, PropertyConstants.TRUE);
         }
      }
   }

   /**
   **  Creates a new application pool from the contents of a property file. Please look at the ConnectionInfo class
   **  for documentation of what should be contained in the property file.
   **/
   static public void registerApplicationFromPropertyFile(String sPropFileName)
   {
      try
      {
         Properties properties = (Properties)mLoadedProperties.get(sPropFileName);
         ConnectionInfo connectInfo = null;
         boolean usingConfig = true;
         if (properties == null)
         {
            // open up the property file
            String sConfigPath = sPropFileName + ".properties";

            // find the property file in the classpath
            System.out.println("Loading from CLASSPATH " + sConfigPath);

            InputStream  in = JBOClass.getResourceAsStream(sConfigPath);

            if(in == null)
            {
               throw new RuntimeException("JSP Registry could not locate runtime property file:" + sConfigPath);
            }

            // load up the properties file
            properties	= new Properties();

            properties.load(in);

            in.close();
            mLoadedProperties.put(sPropFileName, properties);

            // Backwards compatibility since 3.1
            usingConfig = (properties.get("ConfigName") != null);
            if (!usingConfig)
            {
               // this handles backward compatibility
               connectInfo = new ConnectionInfo(properties);
               properties.put("UserName", connectInfo.sUserName);
               properties.put("Password", connectInfo.sPassword);
            }            
         }
         else
         {
            // Backwards compatibility since 3.1
            usingConfig = (properties.get("ConfigName") != null);
            if (!usingConfig)
            {
               // this handles backward compatibility
               connectInfo = new ConnectionInfo(properties);
            }
         }


         // check if we are using a configuration (this started in 3.2)
         ApplicationPool pool = null;
         if(usingConfig)
         {
            String sConfigName = properties.get("ConfigName").toString();
            int index = sConfigName.lastIndexOf('.');
            String sConfigPackage = sConfigName.substring(0, index);
            String sConfigSection = sConfigName.substring(index + 1);

            // strip out the am class
            sConfigPackage = sConfigPackage.substring(0, sConfigPackage.lastIndexOf('.'));

            pool = PoolMgr.getInstance().findPool(
               sPropFileName
               , sConfigPackage
               , sConfigSection
               , properties);
         }
         else
         {
            pool  = PoolMgr.getInstance().findPool(
                           sPropFileName
                           , connectInfo.getPoolClass()
                           , connectInfo.getAppModuleClass()
                           , connectInfo.getConnectionUrl()
                           , connectInfo.getConnectionSettings());

            Hashtable userData = pool.getUserData();
            if (userData != null && userData.isEmpty())
            {
               pool.setUserData(properties);
            }
         }

         // If the user has not specified a custom session cookie factory
         // then make sure that the pool is setup to use the HttpSessionCookieFactory
         SessionCookieFactory factory = pool.getSessionCookieFactory();
         if (PropertyMetadata.ENV_AMPOOL_COOKIE_FACTORY_CLASS_NAME.pDefault.equals(factory.getClass().getName()))
         {
            pool.setSessionCookieFactory(new HttpSessionCookieFactory());
         }
      }
      catch (Exception ex)
      {
         ex.printStackTrace();
         throw new RuntimeException(ex.toString());
      }
   }

   /**
    * Helper method to obtain the specified application's release mode.
    */
   public String getReleaseMode(String applicationId)
   {
      Hashtable appProps = getAppSettings(applicationId);

      String releaseMode =
         ((appProps != null)
            && (appProps.get(PropertyMetadata.AM_RELEASE_MODE.pName) != null))
         ? (String)appProps.get(PropertyMetadata.AM_RELEASE_MODE.pName)
         : null;

      // If the stateless runtime application property value is true then set
      // the release mode to be stateful.  Otherwise set the release mode to be
      // reserved.
      // Required for backwards compatibility with 3.1
      if ((releaseMode == null)
         && (appProps != null)
         && (appProps.get(PropertyConstants.IS_STATELESS_RUNTIME) != null))
      {
         releaseMode =
            ((String)appProps.get(PropertyConstants.IS_STATELESS_RUNTIME))
               .equals(PropertyConstants.TRUE)
            ? STATEFUL
            : RESERVED;
      }

      // Finally, if the release mode is still null set it to be reserved.
      if (releaseMode == null)
      {
         releaseMode = RESERVED;
      }

      return releaseMode;
   }

   /**
    * @deprecated the sessionId is now managed by the SessionCookie.
    * Application developers wishing to override sessionId generation should
    * create a custom SessionCookieFactory.
    * <p>
    * Application developers wishing to override how snapshot id(s) are stored
    * and/or loaded should override:
    * <p>
    * {@link oracle.jbo.http.HttpSessionCookieImpl#writeValue(Object sink)
    * {@link oracle.jbo.http.HttpSessionCookieImpl#readValue(Object source)
    * <p>
    * @since 5.0
    * @see oracle.jbo.http.HttpSessionCookieHelper#readCookieValue(HttpServletRequest, String)
    */
   protected String readSessionId(
      HttpServletRequest request
      , String applicationId)
   {
      HttpContainer container = HttpContainer.getInstanceFromSession(request.getSession(true));
      SessionCookie cookie = container.getSessionCookie(applicationId);
      String value = null;
      if (cookie != null)
      {
         value = cookie.readValue(request);
      }
      return value;
   }

   /**
    * @deprecated the sessionId is now managed by the SessionCookie.
    * Application developers wishing to override sessionId generation should
    * create a custom SessionCookieFactory.
    * <p>
    * Application developers wishing to override how snapshot id(s) are stored
    * and/or loaded should override:
    * <p>
    * {@link oracle.jbo.http.HttpSessionCookieImpl#writeValue(Object sink)
    * {@link oracle.jbo.http.HttpSessionCookieImpl#readValue(Object source)
    * <p>
    * @since 5.0
    * @see oracle.jbo.http.HttpSessionCookieHelper#writeCookieValue(HttpServletResponse, String, String)
    */
   protected void writeSessionId(
      HttpServletResponse response
      , String applicationId
      , String sessionId)
   {
      HttpSessionCookieHelper helper = HttpSessionCookieHelperManager.getHttpSessionCookieHelper();
      helper.writeCookieValue(response, applicationId, sessionId);
   }

   private void addAppModuleToPageContext(
      String applicationId
      , ApplicationModule appModule
      , PageContext pageContext)
   {
      // Use getAttribute instead of findAttribute.  findAttribute will locate
      // the container in the session context if not located in the pageContext.
      HttpContainer container = (HttpContainer)pageContext.getAttribute(HttpContainer.PAGE_CONTEXT_CONTAINER_NAME, PageContext.REQUEST_SCOPE);

      if (container == null)
      {
         container = new HttpContainer(pageContext);

         pageContext.setAttribute(HttpContainer.PAGE_CONTEXT_CONTAINER_NAME, container, PageContext.REQUEST_SCOPE);
      }

      String amKey = HttpContainer.APPLICATION_PREFIX + applicationId;
      if (container.getValue(amKey) == null)
      {
         container.putValue(amKey, appModule, null);
      }
   }

   /**
    * @deprecated use HttpContainer.getInstanceFromSession(session) instead
    * @since 5.0
    * @see oracle.jbo.http.HttpContainer
    * @see oracle.jbo.http.HttpSessionCookie
    */
   public static HttpContainer getHttpContainer(HttpSession session)
   {
       return HttpContainer.getInstanceFromSession(session);
   }
}
