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

  $Archive: /njcl_v2rmi/src/com/novell/service/session/bindery/BinderyInitialSessionState.java $
  $Revision: 30 $
  $Modtime: 1/12/01 1:08p $

  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 java.util.Vector;
import com.novell.service.session.xplat.*;
import com.novell.service.session.*;
import com.novell.service.session.spi.*;
import com.novell.service.jncp.NSIException;
import com.novell.service.session.util.Debug;

/** @internal
 * BinderySession provider's initial state.
 */
public class BinderyInitialSessionState 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 FAIL_DEBUG = false; // when eval fails
   final static private boolean I_DEBUG = false; // Ignore exception
   final static private boolean S_DEBUG = false; // May have side effects

   public BinderyInitialSessionState
   (
      SessionImpl attachedSession
   )
   throws SessionException, RemoteException
   {
      super(attachedSession);

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

   /**
    * Inherited from Session
    *
    * @see Session#getSession
    */
   public Session getSession
   (
      String domainName,
      SessionEnv environment
   )
   throws SessionException, RemoteException
   {
      Session session;
      String uDomainName = domainName.toUpperCase();
      validateChildren();
      session = getChild(uDomainName);
      if (null == session)
      {
         if (FAIL_DEBUG)
         {
            Debug.printlnOnly("Failed as existing server: '" +
               uDomainName + "'");
         }
         // Doesn't exist...return new
         try
         {
            session = this.addNewSession(
               uDomainName,
               environment);
         }
         catch (Exception e)
         {
            if (I_DEBUG || FAIL_DEBUG)
            {
               Debug.printlnOnly("Failed as new server: '" +
                  uDomainName + "'");
            }
            if (I_DEBUG)
            {
               Debug.ignoreException(e);
            }
            throw new InvalidDomainNameException(uDomainName, e);
         }

         if (DEBUG)
         {
            Debug.println("Added server");
         }
      }
      if (DEBUG)
      {
         Debug.println("Session = " + session);
      }
      return session;
   }

   /**
    * 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
         String attrIds[] =
         {
            Session.PROVIDER_NAME_ATTR_ID,
            Session.SESSION_TYPE_ATTR_ID,
            Session.IS_REAL_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 this state's attributes
         SessionAttrs attributes = 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,
               Session.INITIAL_SESSION_TYPE);
         }
         if (Session.PROVIDER_NAME_ATTR_ID.equals(attrIds[i]))
         {
            attributes.modify(
               Session.PROVIDER_NAME_ATTR_ID,
               Bindery.PROVIDER_NAME);
         }
         if (Session.IS_REAL_ATTR_ID.equals(attrIds[i]))
            attributes.add(
               Session.IS_REAL_ATTR_ID,
               new Boolean(false));
      }
      return attributes;
   }

   protected void validateChildren
   (
   )
   throws SessionException, RemoteException  //this method is not a remote method, but calls one, so must throw RemoteException
   {
      if (DEBUG)
      {
         Debug.println("Entry");
      }
      Connections conns = xplatUtil.getBinderyConnections();
      SessionEnumerator sessionEnum = getChildren();
      ConnectionEnumerator connEnum;
//      String attrIds[] = {Xplat.CONN_CONNECTION_REFERENCE_ATTR_ID};

       // Validate existing sessions: if ref exists in com.novell.service.session, but not
       // in real world, remove com.novell.service.session.
      while (sessionEnum.hasMoreElements())
      {
         Session session = sessionEnum.next();
         if (DEBUG)
         {
            Debug.println(
               "Validating:" + session);
         }
         int sessionRef = 0;
         try
         {
             // Split assignments for easy debug
/*
            SessionAttrs attributes = session.getAttributes(attrIds);

            Integer value = (Integer)attributes.getValue(attrIds[0]);
            sessionRef = value.intValue();
*/
            BinderyServerSessionState state = (BinderyServerSessionState)
               ((SessionImpl)session).getState();
            sessionRef = xplatUtil.getReference(state.getConnection());
         }
         catch (Exception e)
         {
            if (I_DEBUG)
            {
               Debug.ignoreException("Assume invalid", e);
            }
         }
         boolean found = false;

         if (null != conns.get(sessionRef))
         {
            found = true;
             // Don't need to check next time
            conns.remove(sessionRef);
         }
         else
         {
            if (DEBUG)
            {
               Debug.println(
                  "Session not found in requester: " + session);
            }
            InvalidSessionState.makeInvalid(
               (SessionImpl)session,
               new SessionException("Session not found in requester"));
         }
      }

       // Add new sessions: any remaining conns must be new sessions.
      connEnum = conns.elements();
      while (connEnum.hasMoreElements())
      {
         Connection connection = connEnum.next();

         try
         {
            // Remove...just pass connection?
            String name = xplatUtil.getInfoString(connection, Natives.CONN_INFO_SERVER_NAME);
            this.addNewSession(
               connection,
               name.toString(),
               new SessionEnv());
         }
         catch (Exception e)
         {
            if (I_DEBUG)
            {
               Debug.ignoreException("Don't add...assume invalid", e);
            }
         }
      }
      if (DEBUG)
      {
         Debug.println("Exit");
      }
   }

   /**
    * Add Session to existing children, no questions asked.
    */
   private Session addNewSession
   (
      String domainName,
      SessionEnv  environment
   )
   throws SessionException, RemoteException  //this method is not a remote method, but calls one, so must throw RemoteException
   {
      return addNewSession(
         null,
         domainName,
         environment);
   }

   /**
    * Add Session to existing children, no questions asked.
    */
   private Session addNewSession
   (
      Connection  connection,
      String      domainName,
      SessionEnv  environment
   )
   throws SessionException, RemoteException  //this method is not a remote method, but calls one, so must throw RemoteException
   {
      if (DEBUG)
      {
         Debug.println("->BISS:addNewSession(): " +
            connection + ":" + domainName);
      }

      SessionImpl newSession;

//      synchronized (this.attachedSession)
      {
         if(sessionManager.useCustomSockets())
            newSession = new SessionImpl(this.attachedSession, domainName,
               (SessionEnv)environment.clone(), sessionManager.getCustomSocketFactories());
         else
            newSession = new SessionImpl(this.attachedSession, domainName,
               (SessionEnv)environment.clone());

         new BinderyServerSessionState(
            newSession,
            connection);

         attachedSession.addChild(newSession);
      }

      if (DEBUG)
      {
         Debug.println("<-BISS:addNewSession():" + newSession);
      }

      return newSession;
   }
}

