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

  $Archive: /njcl_v2rmi/src/com/novell/service/nw/NetWareInitialContextFactory.java $
  $Revision: 19 $
  $Modtime: 8/24/01 11:34a $
 
  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.service.nw;

import javax.naming.*;
import javax.naming.spi.*;
import java.util.*;
import com.novell.utility.naming.URLParser;
import com.novell.service.session.*;
import com.novell.service.session.xplat.*;

/**
* Creates different NetWare Initial Contexts depending on the
* Context.PROVIDER_URL entry.
*/
public class NetWareInitialContextFactory
implements javax.naming.spi.InitialContextFactory
{
   private boolean containsDomainName(
         String path,
         StringBuffer domainName,
         StringBuffer NetWareContextType,
         StringBuffer newSchemeType)
      throws InvalidNameException
   {
      boolean moreStringLeft = false;

      if(path == null)
      {
         NetWareContextType.append(NetWareStrings.ROOT);
      }
      else if(path.startsWith(NetWareStrings.TREES))
      {
         NetWareContextType.append(NetWareStrings.TREES);
         int len = NetWareStrings.TREES.length();
         if(path.length() > len)
         {
            newSchemeType.append(NetWareStrings.NDS_SCHEME);
            domainName.append(path.substring(len+1)); //skip the slash
            moreStringLeft = true;
         }
      }
      else if(path.startsWith(NetWareStrings.SERVERS))
      {
         NetWareContextType.append(NetWareStrings.SERVERS);
         int len = NetWareStrings.SERVERS.length();
         if(path.length() > len)
         {
            newSchemeType.append(NetWareStrings.SERVER_SCHEME);
            domainName.append(path.substring(len+1)); //skip the slash
            moreStringLeft = true;
         }
      }
      else
         throw new InvalidNameException();

      return moreStringLeft;
   }

   /** Creates an initial context based on the Context.PROVIDER_URL entry passed in the
    *  hash parameter. <p>The syntax for the URL is
    *  [[NetWare://][&lt;SapHost&gt;]/"Trees | Servers"/&lt;DomainName&gt;] If the URL
    *  is not set or is empty, a NetWareInitialContext will be returned. The optional
    *  SapHost is for backwards compatability with older client libraries only. The
    *  NetWare name space tries SLP to list the available trees and servers and ignores
    *  the SapHost name. If SLP is not available on an older client, the SapHost will be
    *  queried by the NetWare name space when it lists trees and servers. If the SapHost
    *  is not set, a default session will be used. If the remaining portion of the URL
    *  contains a domain name, either a Tree context or a Server context will be returned.
    *  <p>The NetWare name space will use the default public SessionManager unless the
    *  com.novell.utility.naming.Environment.SESSION_MANAGER_OBJECT key is set in the
    *  Hashtable parameter.
    *
    * @param     hash  Contains information that determines what context
    *                  is to be returned.
    * @return    The Context created.
    *
    * @exception NamingException When an error occurs.
    */
   public Context getInitialContext(Hashtable hash) throws NamingException
	{
      try
      {
         Session session = null;
         URLParser url;
         Context ctx = null;
         String path, sapHost;
         StringBuffer domainName = new StringBuffer(), type = new StringBuffer();
         StringBuffer newScheme  = new StringBuffer(), temp = new StringBuffer();
         Vector storedExceptions = new Vector();

         Hashtable info = (Hashtable) ((hash!=null) ? (hash.clone()) : new Hashtable());
         url = new URLParser((String)info.get(Context.PROVIDER_URL));

         path = url.getPath();
         if(!containsDomainName(path, domainName, type, newScheme))
         {  //return a NetWare context
            SessionManager sm = (SessionManager)info.get(
               com.novell.utility.naming.Environment.SESSION_MANAGER_OBJECT);
            if(sm == null)
            {
               SessionEnv env = new SessionEnv();
               sm = SessionManagerFactory.getSessionManager(env);
               info.put(com.novell.utility.naming.Environment.SESSION_MANAGER_OBJECT, sm);
            }

            sapHost = url.getHost();
            if((sapHost != null) && (sapHost.length() != 0))
            {
               try
               {
                  session = sm.getSessionTop(sapHost);
                  session.getService(CallsService.KEY); //make sure we can get a CallsService
               }
               catch(SessionException e)
               {
                  throw new InvalidDomainNameException(
                     "No CallsService available from saphost:" + sapHost, e);
               }
            }
            else
            {
               SessionAttrs attrs = new SessionAttrs();
               attrs.add(Session.IS_REAL_ATTR_ID, new Boolean(true));
               attrs.add(Session.SESSION_TYPE_ATTR_ID, Xplat.SERVER_SESSION_TYPE);
               SessionEnumerator enum = sm.search(attrs);
               while(enum.hasMoreElements()) //loop until we get a CallsService
               {
                  try
                  {
                     session = enum.next();
                     session.getService(CallsService.KEY);
                     break;
                  }
                  catch(SessionException se)
                  {
                     storedExceptions.addElement(se);
                     session = null;
                  }
               }
               if(session==null)
               {
                  SessionManager privateSM = SessionManagerFactory.getPrivate(new SessionEnv());
                  SessionEnumerator enumer = privateSM.search(attrs);
                  while(enumer.hasMoreElements())
                  {
                     try
                     {
                        session = enumer.next();
                        session.getService(CallsService.KEY);
                        session = sm.getSession(session.getDomainName());
                        session.getService(CallsService.KEY);
                        break;
                     }
                     catch(SessionException se)
                     {
                        storedExceptions.addElement(se);
                        session = null;
                     }
                  }
               }
               if(session==null)
               {
                  InvalidDomainNameException e = new InvalidDomainNameException("Unable to obtain"
                     + " CallsService from any sessions in this SessionManager.");
                  e.setRootCauses(storedExceptions);
                  throw e;
               }
            }

            info.put(com.novell.utility.naming.Environment.SESSION_OBJECT, session);
            ctx = (Context)new NetWareObjectFactory().getObjectInstance(
               type.toString(), null, null, info);
         }
         else  //return a NDS or Server context
         {
            String newURLString = newScheme.toString() + "://" + domainName.toString();
            info.put(Context.PROVIDER_URL, newURLString);
            if(newScheme.toString().equals(NetWareStrings.NDS_SCHEME))
            {
               ctx = (Context)NamingManager.getObjectInstance(
                  new com.novell.service.nds.naming.ReferenceFactoryImpl().
                     createReference(info),
                  null,
                  null,
                  info);
            }
            else
            {
               ctx = (Context)NamingManager.getObjectInstance(
                  new com.novell.service.server.ReferenceFactoryImpl().
                     createReference(info),
                  null,
                  null,
                  info);
            }
         }
         if(ctx == null)
            throw new NoInitialContextException();
         return ctx;
      }
      catch(NamingException e)
      {
         throw e;
      }
      catch(Exception e)
      {
         NoInitialContextException ne = new NoInitialContextException();
         ne.setRootCause(e);
         throw ne;
      }
	}
}