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

  $Archive: /njcl_v2rmi/src/com/novell/service/session/nds/NDSServerSessionState.java $
  $Revision: 41 $
  $Modtime: 1/10/02 3:30p $

  Copyright (c) 1997 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.service.session.nds;

import java.rmi.RemoteException;
import com.novell.service.session.xplat.*;
import com.novell.service.jncpv2r.net.NetService;
import com.novell.service.jncpv2r.net.NetServiceWrapper;
import com.novell.service.jncpv2r.net.BasicNetService;
import com.novell.service.jncpv2r.net.AliasNetService;
import com.novell.service.jncpv2r.net.NetGetServerDNService;
import com.novell.service.jncpv2r.net.BasicNetGetServerDNService;
import com.novell.service.session.*;
import com.novell.service.session.spi.*;
import com.novell.service.session.util.Debug;
import com.novell.service.jncp.NSIException;
import com.novell.service.session.util.Debug;
import com.novell.java.security.Authenticator;

/** @internal
 */
public class NDSServerSessionState extends NDSContextSessionState
{
   // Need to authenticate all connections...this should be a short-term fix!
   private boolean NLM_KLUDGE_AUTHCONN = true;

   // Always access debug via final static...hopefully a final static of
   // false will be optimized out by the compiler
   final static private boolean DEBUG = false;
   final static private boolean I_DEBUG = false; // Ignore exception
   final static private boolean S_DEBUG = false; // May have side effects

   // Print message if deprecated API is used
   final static private boolean ERROR_ON_DEPRECATED = false;

   public NDSServerSessionState
   (
      SessionImpl attachedSession,
      NDSContext context
   )
   throws SessionException, RemoteException
   {
      super(attachedSession, context);

      // We're ready to be used!
      this.attachedSession.setState(this);
   }

   /**
    * @deprecated Use com.novell.service.security and related packages.
    *
    * Inherited from Authenticatable.
    *
    * @exception SessionException Or a subclass thereof.
    */
   public void authenticate
   (
   )
   throws SessionException, RemoteException
   {
      if (ERROR_ON_DEPRECATED)
      {
         System.out.println("This API has been deprecated..." +
            "see documentation for more details. Stack trace follows:");
         Thread.dumpStack();
      }

      if (DEBUG)
      {
         Debug.println("NSSS.authenticate(): " +
            getDomainName() +
            " : " + this);
      }
      if (isAuthenticated())
         throw new AlreadyAuthenticatedException();
      else
      {
         authenticateUsingParent();
         if (!isAuthenticated())
            throw new UnableToAuthenticateException("Parent failure.");
      }
   }

   /**
    * @deprecated Use com.novell.service.security and related packages.
    *
    * Inherited from Authenticatable
    *
    * name is ignored.
    *
    * @see Authenticatable#authenticate()
    */
   public void authenticate
   (
      String name
   )
   throws SessionException, RemoteException
   {
      if (ERROR_ON_DEPRECATED)
      {
         System.out.println("This API has been deprecated..." +
            "see documentation for more details. Stack trace follows:");
         Thread.dumpStack();
      }

      if (DEBUG)
      {
         Debug.println("NSSS.authenticate(): " +
            getDomainName() +
            " : " + name +
            " : " + this);
      }
      if (isAuthenticated())
         throw new AlreadyAuthenticatedException();
      else
      {
         authenticateUsingParent();
         if (!isAuthenticated())
            throw new UnableToAuthenticateException("Parent failure.");
      }
   }

   /**
    * @deprecated Use com.novell.service.security and related packages.
    *
    * Inherited from Authenticatable
    *
    * @see Authenticatable#unauthenticate
    */
   public void unauthenticate
   (
   )
   throws SessionException, RemoteException
   {
      if (ERROR_ON_DEPRECATED)
      {
         System.out.println("This API has been deprecated..." +
            "see documentation for more details. Stack trace follows:");
         Thread.dumpStack();
      }

      if (DEBUG)
      {
         Debug.println("NSSS.unauthenticate(): " +
            " : " + this);
      }
      if (!isAuthenticated())
         throw new NotAuthenticatedException();
      else
      {
         Authenticator.logout(createIdentity(context.getName()));
      }
   }

   /*
    * Inherited from SessionState
    */
   protected void releaseResources()
   throws SessionException, RemoteException  //this method is not a remote method, but calls one, so must throw RemoteException
   {
      NDSContext context = getContext();
      try
      {
         Connection connection = null;
         try
         {
            connection = context.getConnectionIfAvail();
         }
         catch (Exception e)
         {
            if (I_DEBUG)
            {
               Debug.ignoreException(e);
            }
         }

//         context.close();
         super.releaseResources();

         if (null != connection)
            connection.closeRef();
      }
      catch (NSIException e)
      {
         throw InvalidSessionState.makeInvalid(this.attachedSession, e);
      }
   }

   /**
    * Inherited from Session
    *
    * @see Session#getAttributes()
    */
   public SessionAttrs getAttributes
   (
   )
   throws SessionException, RemoteException
   {
      try
      {
         // Get inherited attributes
         SessionAttrs attributes = super.getAttributes();

         // Override with this session's
         if (forceOperationalAttributes(
            getEffectiveEnvironment()))
            attributes.modify(
               xplatUtil.getAttributes(
                  getContext().
                  getConnection()));

         String attrIds[] =
         {
            Session.SESSION_TYPE_ATTR_ID
         };
         attributes.modify(getStateAttrs(attrIds));

         return attributes;
      }
      catch (NSIException e)
      {
         throw InvalidSessionState.makeInvalid(this.attachedSession, e);
      }
   }

   /**
    * Inherited from Session
    *
    * @see Session#getAttributes(String[])
    */
   public SessionAttrs getAttributes
   (
      String attrIds[]
   )
   throws SessionException, RemoteException
   {
/*
      try
      {
         // Get inherited attributes
         SessionAttrs attributes = super.getAttributes(attrIds);

         // Override with this session's
         attributes.modify(getContext().getConnection().getAttributes(attrIds));
         attributes.modify(getStateAttrs(attrIds));

         return attributes;
      }
      catch (NSIException e)
      {
         throw InvalidSessionState.makeInvalid(this.attachedSession, e);
      }
*/
      try
      {
         SessionAttrs attributes = new SessionAttrs();

         // Get this session's attributes
         attributes = xplatUtil.getAttributes(
            getContext().
            getConnection(),
            attrIds);

         if (attributes.count() != attrIds.length)
         {
            // Get this state's attributes
            attributes.merge(getStateAttrs(attrIds));

            if (attributes.count() != attrIds.length)
            {
               // Get inherited attributes
               attributes.merge(super.getAttributes(attrIds));
            }
         }

         return attributes;
      }
      catch (NSIException e)
      {
         throw InvalidSessionState.makeInvalid(this.attachedSession, e);
      }
   }

   private SessionAttrs getStateAttrs
   (
      String attrIds[]
   )
   throws SessionException
   {
      // Get inherited attributes
      SessionAttrs attributes = new SessionAttrs();

      // Override with this session's
      for (int i = 0; i < attrIds.length; i++)
      {
         if (Session.SESSION_TYPE_ATTR_ID.equals(attrIds[i]))
         {
            attributes.modify(
               Session.SESSION_TYPE_ATTR_ID,
               Xplat.SERVER_SESSION_TYPE);
         }
         if (NDS.SERVER_INFO_DS_VERSION_ATTR_ID.equals(attrIds[i]))
         {
            attributes.modify(
               NDS.SERVER_INFO_DS_VERSION_ATTR_ID,
               this.context.getDSNLMBuild());
         }
         if (NDS.SERVER_INFO_ROOT_MOST_DEPTH_ATTR_ID.equals(attrIds[i]))
         {
            attributes.modify(
               NDS.SERVER_INFO_ROOT_MOST_DEPTH_ATTR_ID,
               this.context.getDSServerRootDepth());
         }
         if (NDS.SERVER_INFO_IS_MASTER_ATTR_ID.equals(attrIds[i]))
         {
            attributes.modify(
               NDS.SERVER_INFO_IS_MASTER_ATTR_ID,
               this.context.isMasterReplica());
         }
         if (NDS.SERVER_INFO_DN_ATTR_ID.equals(attrIds[i]))
         {
            attributes.modify(
               NDS.SERVER_INFO_DN_ATTR_ID,
               this.context.getServerDN());
         }
      }
      return attributes;
   }

   /**
    * Inherited from Session
    *
    * @see Session#getSession
    */
   public Session getSession
   (
      String domainName,
      SessionEnv environment
   )
   throws SessionException, RemoteException
   {
      throw new InvalidStateException("Terminal node");
   }


   /**
    * Inherited from Session
    *
    * @see Session#getService
    */
   public SessionService getService
   (
      String serviceKey
   )
   throws SessionException, RemoteException
   {
      if (DEBUG)
      {
         Debug.println("NSSS.getService(): " +
            getDomainName() +
            " : " + getContext().getConnection());
      }
      isAuthenticated();
      try
      {
         if (serviceKey.equals(CallsService.KEY))
         {
            if(sessionManager.useCustomSockets())
               return new CallsServiceWrapper(new CallsServiceImpl(
                  getContext().getConnection(), sessionManager.getCustomSocketFactories()));
            else
               return new CallsServiceWrapper(new CallsServiceImpl(
                  getContext().getConnection()));
         }
         if (serviceKey.equals(SemaphoreService.KEY))
         {
            if(sessionManager.useCustomSockets())
               return new SemaphoreServiceWrapper(new SemaphoreServiceImpl(
                  getContext().getConnection(), sessionManager.getCustomSocketFactories()));
            else
               return new SemaphoreServiceWrapper(new SemaphoreServiceImpl(
                  getContext().getConnection()));
         }
         if(serviceKey.equals(NCPService.KEY))
         {
            if(sessionManager.useCustomSockets())
               return new NCPServiceWrapper(new BasicNCPService(
                  getContext().getConnection(), sessionManager.getCustomSocketFactories()));
            else
               return new NCPServiceWrapper(new BasicNCPService(
                  getContext().getConnection()));
         }
         if (serviceKey.equals(BasicNetService.KEY))
         {
            if(sessionManager.useCustomSockets())
               return new NetServiceWrapper(new BasicNetService(
                  getContext().duplicate(), sessionManager.getCustomSocketFactories()));
            else
               return new NetServiceWrapper(new BasicNetService(
                  getContext().duplicate()));
         }
         if (serviceKey.equals(AliasNetService.KEY))
         {
            if(sessionManager.useCustomSockets())
               return new NetServiceWrapper(new AliasNetService(
                  getContext().duplicate(), sessionManager.getCustomSocketFactories()));
            else
               return new NetServiceWrapper(new AliasNetService(
                  getContext().duplicate()));
         }
         if (serviceKey.equals(NetGetServerDNService.KEY))
         {
            if(sessionManager.useCustomSockets())
               return (new BasicNetGetServerDNService(
                  getContext().duplicate(), sessionManager.getCustomSocketFactories()));
            else
               return (new BasicNetGetServerDNService(
                  getContext().duplicate()));
         }
         if (serviceKey.equals(NDSShibboleth.KEY))
         {
            if(sessionManager.useCustomSockets())
               return new ShibbolethWrapper(new NDSShibboleth(
                  (SessionImpl)attachedSession, sessionManager.getCustomSocketFactories()));
            else
               return new ShibbolethWrapper(new NDSShibboleth(
                  (SessionImpl)attachedSession));
         }
         if (serviceKey.equals(PersistenceService.KEY))
         {
            if(sessionManager.useCustomSockets())
               return new NDSServerPersistenceService(
                  (SessionImpl)this.attachedSession, sessionManager.getCustomSocketFactories());
            else
               return new NDSServerPersistenceService(
                  (SessionImpl)this.attachedSession);
         }
         if (serviceKey.equals(NetService.KEY))
         {
            if(sessionManager.useCustomSockets())
               return new NetServiceWrapper(new BasicNetService(
                  getContext().duplicate(), sessionManager.getCustomSocketFactories()));
            else
               return new NetServiceWrapper(new BasicNetService(
                  getContext().duplicate()));
         }

         // Add registered services here

      }
      catch (NSIException e)
      {
         throw InvalidSessionState.makeInvalid(this.attachedSession, e);
      }
      return super.getService(serviceKey);
   }

   protected void authenticateUsingParent
   (
   )
   throws SessionException, RemoteException  //this method is not a remote method, but calls one, so must throw RemoteException
   {
      SessionImpl p = (SessionImpl)getParent();

      if (p.isAuthenticated())
      {
         NDSContextSessionState pstate = (NDSContextSessionState)p.getState();
         pstate.context.authenticate(getContext().getConnection());
      }
   }

   /**
    * Inherited from Authenticatable
    *
    * @see Authenticatable#isAuthenticated
    */
   public boolean isAuthenticated
   (
   )
   throws SessionException, RemoteException
   {
      if (DEBUG)
      {
         Debug.println("NSSS: isAuthenticated(): " +
            getDomainName() + " : " + getContext().getConnection());
      }
      try
      {
         Connection connection = getContext().getConnection();
         int authState = xplatUtil.getInfoValue(
            connection,
            Natives.CONN_INFO_AUTHENT_STATE);

         if (NLM_KLUDGE_AUTHCONN)
         {
            if (DEBUG)
            {
               Debug.println("NSSS:KLUDGE!!! ALWAYS AUTHENTICATE");
            }

            if (Natives.AUTH_TYPE_NONE == authState ||
                connection.forceLicense())
               authenticateUsingParent();
         }

         authState = xplatUtil.getInfoValue(
            connection,
            Natives.CONN_INFO_AUTHENT_STATE);

         if (Natives.AUTH_TYPE_NDS == authState)
         {
            if (DEBUG)
            {
               Debug.println("NSSS: isAuthenticated() = !TRUE!!!");
            }
            return true;
         }
         if (DEBUG)
         {
            Debug.println("NSSS: isAuthenticated() = FALSE");
         }
         return false;
      }
      catch (NSIException e)
      {
         throw InvalidSessionState.makeInvalid(this.attachedSession, e);
      }
   }
}

