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

  $Archive: /njcl_v2rmi/src/com/novell/service/session/bindery/BinderyServerSessionState.java $
  $Revision: 21 $
  $Modtime: 1/10/02 3:32p $

  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.bindery;

import java.rmi.RemoteException;
import com.novell.service.session.*;
import com.novell.service.session.spi.*;
import com.novell.service.session.xplat.*;
import com.novell.service.jncp.NSIException;
import com.novell.service.session.util.Debug;
import com.novell.java.security.Authenticator;
import com.novell.java.security.Identity;
import com.novell.java.security.KeyManagementException;
import com.novell.service.security.BinderyIdentity;
import com.novell.service.security.BinderyIdentityScope;

/** @internal
 */
public class BinderyServerSessionState extends BinderySessionState
{
   // 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 ENTRY_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;

   private static final String PROVIDER_NAME = "BINDERY";

   protected Connection connection;

   public BinderyServerSessionState
   (
      SessionImpl attachedSession,
      Connection connection
   )
   throws SessionException, RemoteException
   {
      super(attachedSession);

      if (DEBUG || ENTRY_DEBUG)
      {
         Debug.println("Entry");
      }
      if (null == connection)
      {
         connection = xplatUtil.getConnectionByName(
            getEffectiveEnvironment(),
            getDomainName(),
            Natives.OWNER_BINDERY);
      }
      setConnection(connection);

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

   /*
    * Inherited from SessionState
    */
   protected void releaseResources()
   throws SessionException
   {
      if (DEBUG || ENTRY_DEBUG)
      {
         Debug.println("Entry:" + this);
      }
      xplatUtil.closeRef(this.connection);
      if (DEBUG || ENTRY_DEBUG)
      {
         Debug.println("Exit");
      }
   }

   /**
    * Inherited from Session
    *
    * @see Session#getSession
    */
   public Session getSession
   (
      String domainName,
      SessionEnv environment
   )
   throws SessionException, RemoteException
   {
      if (DEBUG || ENTRY_DEBUG)
      {
         Debug.println("Entry");
      }
      throw new InvalidStateException("Terminal node");
   }

   /**
    * Inherited from Session
    *
    * @see Session#getAttributes()
    */
   public SessionAttrs getAttributes
   (
   )
   throws SessionException, RemoteException
   {
      if (DEBUG || ENTRY_DEBUG)
      {
         Debug.println("Entry");
      }
      try
      {
         // Get inherited attributes
         SessionAttrs attributes = super.getAttributes();

         // Override with this session's
         if (forceOperationalAttributes(getEffectiveEnvironment()))
            attributes.modify(
               xplatUtil.getAttributes(
                  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
   {
      if (DEBUG || ENTRY_DEBUG)
      {
         Debug.println("Entry");
      }
      try
      {
         SessionAttrs attributes = new SessionAttrs();

         // Get this session's attributes
         attributes = xplatUtil.getAttributes(
            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
   {
      if (DEBUG || ENTRY_DEBUG)
      {
         Debug.println("Entry");
      }
      // 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);
         }
      }
      return attributes;
   }

   /**
    * Inherited from Session
    *
    * @see Session#search
    */
   public SessionEnumerator search
   (
      SessionAttrs matchingSessionAttrSet
   )
   throws SessionException, RemoteException
   {
      if (DEBUG || ENTRY_DEBUG)
      {
         Debug.println("Entry");
      }
      throw new InvalidStateException("Terminal node");
   }

   /**
    * Inherited from Session
    *
    * @see Session#getService
    */
   public SessionService getService
   (
      String serviceKey
   )
   throws SessionException, RemoteException
   {
      if (DEBUG || ENTRY_DEBUG)
      {
         Debug.println("Entry");
      }
      if (DEBUG)
      {
         Debug.println("BSSS: getService(): " +
            getDomainName() +
            " : " + getConnection());
      }
      isAuthenticated();
      try
      {
         // Use ==, not equals...must be same reference
         if (serviceKey.equals(BinderyShibboleth.KEY))
         {
            if(sessionManager.useCustomSockets())
               return new ShibbolethWrapper(new BinderyShibboleth(
                  (SessionImpl)attachedSession, sessionManager.getCustomSocketFactories()));
            else
               return new ShibbolethWrapper(new BinderyShibboleth(
                  (SessionImpl)attachedSession));
         }
         if (serviceKey.equals(PersistenceService.KEY))
         {
            if(sessionManager.useCustomSockets())
               return new BinderyServerPersistenceService(
                  (SessionImpl)attachedSession, sessionManager.getCustomSocketFactories());
            else
               return new BinderyServerPersistenceService(
                  (SessionImpl)attachedSession);
         }
         if (serviceKey.equals(CallsService.KEY))
         {
            if(sessionManager.useCustomSockets())
               return new CallsServiceWrapper(new CallsServiceImpl(
                  connection, sessionManager.getCustomSocketFactories()));
            else
               return new CallsServiceWrapper(new CallsServiceImpl(
                  connection));
         }
         if (serviceKey.equals(SemaphoreService.KEY))
         {
            if(sessionManager.useCustomSockets())
               return new SemaphoreServiceWrapper(new SemaphoreServiceImpl(
                  connection, sessionManager.getCustomSocketFactories()));
            else
               return new SemaphoreServiceWrapper(new SemaphoreServiceImpl(
                  connection));
         }

         // Add registered services here

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

      return super.getService(serviceKey);
   }

   /**
    * @deprecated Use com.novell.service.security and related packages.
    *
    * Inherited from Authenticatable
    *
    */
   public void authenticate
   (
      String name
   )
   throws SessionException, RemoteException
   {
      if (DEBUG || ENTRY_DEBUG)
      {
         Debug.println("Entry");
      }
      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("BSSS.authenticate(): " +
            getDomainName() +
            " : " + name +
            " : " + this);
      }
      if (isAuthenticated())
         throw new AlreadyAuthenticatedException();
      else
      {
         Authenticator.login(createIdentity(name));
      }
   }

   /**
    * @deprecated Use com.novell.service.security and related packages.
    *
    * Inherited from Authenticatable
    *
    */
   public void unauthenticate
   (
   )
   throws SessionException, RemoteException
   {
      if (DEBUG || ENTRY_DEBUG)
      {
         Debug.println("Entry");
      }
      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("BSSS.unauthenticate(): " +
            this);
      }
      if (!isAuthenticated())
         throw new NotAuthenticatedException();
      else
      {
         Authenticator.logout(
            createIdentity(getName()));
      }
   }

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

         if (Natives.AUTH_TYPE_BIND != authState)
         {
            if (DEBUG)
            {
               Debug.println("BSSS.isAuthenticated(): !FALSE! state = 0x" +
                  Integer.toHexString(authState));
            }
            return false;
         }
      }
      catch (NSIException e)
      {
         throw InvalidSessionState.makeInvalid(this.attachedSession, e);
      }
      if (DEBUG)
      {
         Debug.println("BSSS.isAuthenticated(): TRUE ");
      }
      return true;
   }

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

      return xplatUtil.getUserName(this.connection);
   }

   /**
    * Inherited from Authenticatable.
    *
    * @see Session#getAttributes(String[])
    */
   public Identity createIdentity
   (
      String userName
   )
   throws SessionException, RemoteException
   {
      if (DEBUG || ENTRY_DEBUG)
      {
         Debug.println("Entry");
      }
      try
      {
         BinderyIdentityScope scope = new BinderyIdentityScope(getDomainName());
         BinderyIdentity id = new BinderyIdentity(userName, scope);

         Session sm = this;
         while (sm.hasParent())
            sm = sm.getParent();
         id.setSessionManager((SessionManager)sm);
         id.setSession((Session)attachedSession);
         return id;
      }
      catch (KeyManagementException e)
      {
         throw new SessionException("Unable to instantiate Identity", e);
      }
   }

   public String toString()
   {
      StringBuffer s = new StringBuffer();
      try
      {
         if (null != connection)
            s.append(
               xplatUtil.toString(connection));
      }
      catch (Exception e)
      {
         if (I_DEBUG)
         {
            Debug.ignoreException("unexpected", e);
         }
      }
      return (super.toString() + ":" + s);
   }

   /**
    * Make sure get/set synchronized...avoid read/write synch problems.
    */
//   synchronized protected void setConnection(Connection connection)
   protected void setConnection(Connection connection)
   {
      if (DEBUG || ENTRY_DEBUG)
      {
         Debug.println("Entry");
      }
      this.connection = connection;
   }

   /**
    * Make sure get/set synchronized...avoid read/write synch problems.
    */
//   synchronized protected Connection getConnection()
   protected Connection getConnection()
   {
      if (DEBUG || ENTRY_DEBUG)
      {
         Debug.println("Entry");
      }
      return this.connection;
   }
}

