/* **************************************************************************

  $Archive: /njcl_v2/src/com/novell/utility/naming/Environment.java $
  $Revision: 12 $
  $Modtime: 3/01/00 11:20a $
 
  Copyright (c) 1998 Novell, Inc.  All Rights Reserved.

  THIS WORK IS  SUBJECT  TO  U.S.  AND  INTERNATIONAL  COPYRIGHT  LAWS  AND
  TREATIES.   NO  PART  OF  THIS  WORK MAY BE  USED,  PRACTICED,  PERFORMED
  COPIED, DISTRIBUTED, REVISED, MODIFIED, TRANSLATED,  ABRIDGED, CONDENSED,
  EXPANDED,  COLLECTED,  COMPILED,  LINKED,  RECAST, TRANSFORMED OR ADAPTED
  WITHOUT THE PRIOR WRITTEN CONSENT OF NOVELL, INC. ANY USE OR EXPLOITATION
  OF THIS WORK WITHOUT AUTHORIZATION COULD SUBJECT THE PERPETRATOR TO
  CRIMINAL AND CIVIL LIABILITY.

****************************************************************************/

package com.novell.utility.naming;


import java.io.Serializable;

import java.util.Hashtable;

import javax.naming.*;

import com.novell.service.session.*;


/**
 * Provides constants for environment variables associated with Novell 
 * JNDI providers.
 */
public abstract class Environment implements Cloneable, Serializable
{
   // Program configuration JNDI Environment Properties ======================
   /**
    * Environment variable name for JNDI initial context factory.
    *
    * <p>Class name of initial context factory to use.
    *
    * <p>(INITIAL_CONTEXT_FACTORY = Context.INITIAL_CONTEXT_FACTORY)
    * </p>
    */
   public final static String INITIAL_CONTEXT_FACTORY
                                          = Context.INITIAL_CONTEXT_FACTORY;
   /**
    * Environment variable name for JNDI object factory.
    *
    * <p>Colon-separated list of class names of object factory classes to use.
    *
    * <p>(OBJECT_FACTORIES = Context.OBJECT_FACTORIES)
    * </p>
    */
   public final static String OBJECT_FACTORIES
                                          = Context.OBJECT_FACTORIES;
   /**
    * Environment variable name for JNDI URL package prefixes.
    *
    * <p>Colon-separated list of package prefixes to use when loading in URL
    * context factories.
    *
    * <p>(URL_PKG_PREFIXES = Context.URL_PKG_PREFIXES)
    * </p>
    */
   public final static String URL_PKG_PREFIXES
                                          = Context.URL_PKG_PREFIXES;
   // Access Configuration JNDI Environment Properties =======================
   /**
    * Environment variable name for JNDI provider URL.
    *
    * <p>Specifies configuration information for provider to use.
    *
    * <p>(PROVIDER_URL = Context.PROVIDER_URL)
    * </p>
    */
   public final static String PROVIDER_URL 
                                          = Context.PROVIDER_URL;
   /**
    * Environment variable name for JNDI DNS URL.
    *
    * <p>Specifies the DNS host and domain names to use for the JNDI URL
    * context.
    *
    * <p>(DNS_URL = Context.DNS_URL)
    * </p>
    */
   public final static String DNS_URL 
                                          = Context.DNS_URL;

   // Service-Related JNDI Environment Properties ============================
   /**
    * Environment variable name for JNDI authoritative setting.
    *
    * <p>Specifies the authoritativeness of the service requested. If "true",
    * specifies most authoritative source is to be used (e.g. bypass any
    * caches, or bypass replicas in some systems). Otherwise, source need not
    * be (but can be) authoritative. When unspecified, defaults to false.
    *
    * <p>(AUTHORITATIVE = Context.AUTHORITATIVE)
    * </p>
    */
   public final static String AUTHORITATIVE
                                          = Context.AUTHORITATIVE;
   /**
    * Environment variable name for JNDI batch size setting.
    *
    * <p>Specifies the preferred batch size to use when returning data via
    * the service's protocol. This is a hint to the provider to return the
    * results of operations in batches of the specified size, so that the
    * provider can optimize its performance and usage of resources. When
    * unspecified, it is determined by provider.
    *
    * <p>(BATCHSIZE = Context.BATCHSIZE)
    * </p>
    */
   public final static String BATCHSIZE
                                          = Context.BATCHSIZE;
   /**
    * Environment variable name for JNDI referral setting.
    *
    * <p>Specifies that referrals encountered by the service provider are to
    * be followed automatically. If "follow", follow referrals automatically.
    * If "ignore", ignore referrals encountered. If "throw", throw
    * ReferralException when a referral is encountered. When unspecified,
    * determined by provider.
    *
    * <p>(REFERRAL = Context.REFERRAL)
    * </p>
    */
   public final static String REFERRAL
                                          = Context.REFERRAL;

   // Security JNDI Environment Properties ===================================
   /**
    * Environment variable name for JNDI security protocol setting.
    *
    * <p>Security protocol to use for service. When unspecified, determined by
    * provider.
    *
    * <p>(SECURITY_PROTOCOL = Context.SECURITY_PROTOCOL)
    * </p>
    */
   public final static String SECURITY_PROTOCOL
                                          = Context.SECURITY_PROTOCOL;
   /**
    * Environment variable name for JNDI security authentication setting.
    *
    * <p>Takes values "none", "simple", "strong", or a provider specific
    * string (e.g. "CRAM_MD5"). When unspecified, determined by provider.
    *
    * <p>(SECURITY_AUTHENTICATION = Context.SECURITY_AUTHENTICATION)
    * </p>
    */
   public final static String SECURITY_AUTHENTICATION
                                          = Context.SECURITY_AUTHENTICATION;
   /**
    * Environment variable name for JNDI security principal setting.
    *
    * <p>Identity of principal (e.g. user) for the authentication scheme. When
    * unspecified, defaults to the identity (specific to the authentication
    * scheme selected) or user running the application.
    *
    * <p>(SECURITY_PRINCIPAL = Context.SECURITY_PRINCIPAL)
    * </p>
    */
   public final static String SECURITY_PRINCIPAL
                                          = Context.SECURITY_PRINCIPAL;
   /**
    * Environment variable name for JNDI security credentials setting.
    *
    * <p>Principal's credentials for the authentication scheme. When
    * unspecified, obtained by the provider on behalf of the user, using the
    * security infrastructure available to the provider. Examples of different
    * types of credentials are passwords, keys, and certificates. The
    * particular type of credentials is determined by the authentication
    * scheme chosen.
    *
    * <p>(SECURITY_PROTOCOL = Context.SECURITY_PROTOCOL)
    * </p>
    */
   public final static String SECURITY_CREDENTIALS
                                          = Context.SECURITY_CREDENTIALS;
   // Internationalization JNDI Environment Properties =======================
   /**
    * Environment variable name for JNDI language setting.
    *
    * <p>Specifies a colon-separated list of preferred languages to use with
    * this service (e.g. "en-US", "fr", "fr-CH", "ja-JP-kanji"). Languages are
    * specified using tags defined in RFC 1766. When unspecified, the language
    * preference - if any - is determined by the provider.
    *
    * <p>(LANGUAGE = Context.LANGUAGE)
    * </p>
    */
   public final static String LANGUAGE
                                          = Context.LANGUAGE;

   // Novell custom parameters ===============================================
   // Novell session parameters ==============================================
   /**
    * The environment variable name for the NetWare session.
    *
    * <p>Any context that is communicating with a NetWare server will have
    * a session object. This session object can be obtained and used for the
    * purpose of authentication, or session management operations.
    *
    * <p>(SESSION_OBJECT = "com.novell.service.naming.session")
    * </p>
    * @see #getSession
    */
   public final static String SESSION_OBJECT = "java.naming.session";

   /**
    * The environment variable name for the NetWare session manager.
    *
    * <p>Each session belongs to a given session manager. In the event that
    * multiple (private) session managers are in use, this variable can be
    * used to manipulate the scope of the sessions to be used by this
    * context and any of its subordinates.
    *
    * <p>(SESSION_MANAGER_OBJECT =
    * "com.novell.service.naming.session.manager")
    * </p>
    * @see #getSessionManager
    */
   public final static String SESSION_MANAGER_OBJECT 
                                = "java.naming.session.manager";

   // Novell transport parameters ============================================
   public final static String NCP_PROTOCOL = "ncp";
   public final static String LDAP_PROTOCOL = "ldap";
   public final static String RMI_PROTOCOL = "rmi";
   public final static String IIOP_PROTOCOL = "iiop";
//   public final static String TRANSPORT_URL = "com.novell.service.naming.transport.url";
   public final static String TRANSPORT_PROTOCOL
                           = "com.novell.service.naming.transport.protocol";

   //SERVICE
//   public final static String SERVICE_VERSION 
//                                          = "java.naming.provider.version";

   // Novell parameter values ================================================
   
   /**
    * The environment value associated with the INITIAL_CONTEXT_FACTORY
    * key to be used for the FileSystem name space.
    *
    * <p>(FS_INITIAL_CONTEXT_FACTORY = 
    * "com.novell.service.file.nw.naming.FileSystemInitialContextFactory")
    * </p>
    */
   public final static String FS_INITIAL_CONTEXT_FACTORY 
        = "com.novell.service.file.nw.naming.FileSystemInitialContextFactory";

   /**
    * The environment value associated with the INITIAL_CONTEXT_FACTORY
    * key to be used for the NetWare name space.
    *
    * <p>(FS_INITIAL_CONTEXT_FACTORY = 
    * "com.novell.service.nw.NetWareInitialContextFactory")
    * </p>
    */
   public final static String NW_INITIAL_CONTEXT_FACTORY 
                     = "com.novell.service.nw.NetWareInitialContextFactory";

   /**
    * The environment value associated with the INITIAL_CONTEXT_FACTORY
    * key to be used for the Server name space.
    *
    * <p>(SERVER_INITIAL_CONTEXT_FACTORY = 
    * "com.novell.service.server.ServerInitialContextFactory")
    * </p>
    */
   public final static String SERVER_INITIAL_CONTEXT_FACTORY 
                    = "com.novell.service.server.ServerInitialContextFactory";

   /**
    * The environment value associated with the INITIAL_CONTEXT_FACTORY
    * key to be used for the NDS name space.
    *
    * <p>(NDS_INITIAL_CONTEXT_FACTORY = 
    * "com.novell.service.nds.naming.NdsInitialContextFactory")
    * </p>
    */
   public final static String NDS_INITIAL_CONTEXT_FACTORY 
                   = "com.novell.service.nds.naming.NdsInitialContextFactory";

   /**
    * The environment value associated with the INITIAL_CONTEXT_FACTORY
    * key to be used for the Queue Management (QMS) name space.
    *
    * <p>(QMS_INITIAL_CONTEXT_FACTORY = 
    * "com.novell.service.qms.naming.QueueInitialContextFactory")
    * </p>
    */
   public final static String QMS_INITIAL_CONTEXT_FACTORY 
                 = "com.novell.service.qms.naming.QueueInitialContextFactory";


   /** @internal
    * The environment is a hashtable used for property storage.
    */
   protected Hashtable environment;

   /** @internal
    * A flag indicating whether the environment is shared.
    */
   private boolean shared;

   /** @internal
    * The current session in use by this Environment.
    */
   protected Session session;


   /** @internal
    * Creates an environment based on a Hashtable.
    *
    * <p>The resulting environment has the same properties as the Hashtable
    * passed in.
    *
    * @param   environment       The properties to use in constructing the new
    *                            Environment.
    */
   public Environment (
         Hashtable environment)
   {
      shared = false;
      this.environment = (Hashtable) environment.clone ();
   }

   /** @internal
    * Creates an environment based on another Environment.
    *
    * <p>The resulting environment has the same properties as the Environment
    * passed in.
    *
    * @param   environment       The properties to use in constructing the new
    *                            Environment.
    */
   public Environment (
         Environment environment)
      throws NamingException
   {
      shared = true;
      environment.setShared ();
      this.environment = environment.getEnvironment (false);

   } /* Environment () */

   /** @internal
    * Adds a new environment property to the environment.
    *
    * @param propName            The non-null name of the environment property
    *                            to add. If already exists in environment,
    *                            overwrite and return old value.
    * @param propVal             The non-null value.
    *
    * @return                    The value that propName used to have in the
    *                            environment; null if not there before.
    *
    * @exception NamingException If a naming exception was encountered.
    *
    * @see #getEnvironment
    * @see #removeFromEnvironment
    */
   public Object addToEnvironment (
         String propName,
         Object propVal)
      throws NamingException
   {
      copyWhenShared ();
      return (environment.put (propName, propVal));
   }

   /** @internal
    * Removes an environment property from the environment.
    *
    * @param propName            The non-null name of the environment property
    *                            to remove.
    * @return                    The value associated with propName; null if
    *                            propName was not in environment.
    *
    * @exception NamingException If a naming exception was encountered.
    *
    * @see #getEnvironment
    * @see #addToEnvironment
    */
   public Object removeFromEnvironment (
         String propName)
      throws NamingException
   {
      copyWhenShared ();
      return (environment.remove (propName));
   }

   /** @internal
    * Retrieves the Hashtable in use by this Environment.
    *
    * @param clone               Flag that determines if the returned 
    *                            environment is the current environment or
    *                            is cloned.  This method should only be 
    *                            called with this flag false, from a 
    *                            sub-class of Environment that knows what 
    *                            they are doing.  This flag should be set to
    *                            true when called from the 
    *                            Context.getEnvironment methods, so the object
    *                            returned to the user layer can not mess up
    *                            this Environment.
    *
    * @return                    The non-null (but possibly empty)
    *                            Hashtable in use by this environment. Caller 
    *                            should not make changes to this object: their
    *                            effect on the context is undefined.  To
    *                            change the environment of the context, use
    *                            addToEnvironment() or removeFromEnvironment().
    *
    * @exception NamingException If a naming exception was encountered.
    * @see #addToEnvironment
    * @see #removeFromEnvironment
    */
   public Hashtable getEnvironment (
         boolean clone)
      throws NamingException
   {
      return (clone ? (Hashtable) environment.clone () : environment);
   }

   /** @internal
    * Creates a copy of this environment with the Hashtable being shared.
    *
    * @return                    A clone of this Environment.
    * @see java.lang.Cloneable
    */
   public Object clone ()
   {
      try
      {
         Environment environment = (Environment) super.clone ();

         environment.environment = this.environment;
         environment.setShared ();
         setShared ();
         environment.session = this.session;
         return (environment);
      }
      catch (CloneNotSupportedException e)
      {
         // this shouldn't happen, since we are Cloneable
         throw (new InternalError ());
      }

   } /* clone () */

   /** @internal
    * Sets the shared flag to true.
    *
    * <p>This method is used to help improve the memory efficiency of multiple
    * Environments. It should only be called by sub-classes that share the
    * same Hashtable.
    */
   public synchronized final void setShared ()
   {
      shared = true;
   }

   /** @internal
    * Copies the environment if it is shared and sets the shared flag to
    * false.
    */
   private synchronized final void copyWhenShared ()
   {
      if (shared)
      {
         environment = (Hashtable) environment.clone ();
         shared = false;
      }

   } /* copyWhenShared () */

   /** @internal
    * Returns the session in use by the owning context.
    *
    * <p>This is equivalant to asking for the SESSION_OBJECT parameter.
    *
    * @exception NamingException If a naming exception was encountered.
    */
   public abstract Session getSession ()
      throws NamingException;

   /** @internal
    * Returns a session service given a service key.
    *
    * @param serviceKey          A string identifying the desired service.
    * @exception NamingException If a naming exception was encountered.
    */
   public SessionService getService (
         String serviceKey)
      throws NamingException
   {
      try
      {
         return (getSession ().getService (serviceKey));
      }
      catch (SessionException e)
      {
         NamingException ne = new AuthenticationException ();

         ne.setRootCause (e);
         throw (ne);
      }

   } /* getService () */


   /** @internal
    * Returns the session manager in use by the owning context.
    *
    * <p>This is equivalant to asking for the SESSION_MANAGER_OBJECT
    * parameter.
    *
    * @exception NamingException If a naming exception was encountered.
    */
   public SessionManager getSessionManager ()
      throws NamingException
   {
      return ((SessionManager) environment.get (SESSION_MANAGER_OBJECT)); 
   }


   /** @internal
    *
    */
   public String getProviderURL ()
      throws NamingException
   {
      String url = (String) environment.get(Context.PROVIDER_URL);

      if (url != null)
      {
         return (url); 
      }
      throw (new NamingException ());

   } /* getProviderURL () */

   /** @internal
    *
    */
   public String getTransportProtocol ()
   {
      String transport = (String) environment.get (TRANSPORT_PROTOCOL);

      if (transport == null) 
      {
         return (NCP_PROTOCOL);
      }
      return (transport.toLowerCase ());

   } /* getTransport () */

} /* Environment */


