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

  $Archive: /njcl/src/com/novell/service/file/nw/naming/ContextFactoryImpl.java $
  $Revision: 5 $
  $Modtime: 4/16/98 10:46a $

  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.file.nw.naming;

import java.util.Hashtable;

import javax.naming.NamingException;
import javax.naming.Reference;
import javax.naming.Context;
import javax.naming.Name;
import javax.naming.CompositeName;
import javax.naming.spi.ObjectFactory;
import javax.naming.directory.DirContext;

/** @internal
 * This class contains factory methods that instantiate appropriate file
 * system contexts given an object.  This factory will produce a context
 * given a valid JNDI Reference; also, it will also handle file system
 * contexts which are passed in.
 */
public class ContextFactoryImpl implements ObjectFactory
{
   static final int CREATE_VOLUME_CONTEXT          = 0;
   static final int CREATE_DIR_CONTEXT             = 1;
   static final int CREATE_FILE_CONTEXT            = 2;
   static final int CREATE_SCHEMA_CONTEXT          = 3;
   static final int CREATE_SCHEMA_CLASSDEF_CONTEXT = 4;
   static final int CREATE_SCHEMA_ATTRDEF_CONTEXT  = 5;
   static final int CREATE_SCHEMA_SYNTAX_CONTEXT   = 6;
   /**
    * Creates a file system context given an object.
    *
    * @param      obj            Object giving information pertinent
    *                            to instantiating the desired object.
    *                            'obj' can be of type
    *                            'javax.naming.Reference'
    *                            with one valid StringRefAddr called:
    *                            'com.novell.service.file.nw.naming.ServerPathRefAddr'.
    *                            -or- 'obj' can be of any file system
    *                            naming system JNDI context.
    * @param      props          Properties that can be used to
    *                            instantiate the object correctly.
    * @return                    This method has the following results:
    *                            <ul>
    *                            <li>If 'obj' is a Reference, but not a valid
    *                            file system Reference, null is returned.
    *                            <li>If 'obj' is a valid file system
    *                            Reference, then an attempt is made at
    *                            constructing the appropriate object.
    *                            If exceptions occur, null is returned.
    *                            <li>If 'obj' is a file system context,
    *                            then 'obj' is returned (setEnvironment() is
    *                            also called with 'props' as the argument).
    *                            <li>If 'obj' is null, null is returned.
    *                            </ul>
    * @exception  Exception      When an error occurs instantiating the
    *                            object specified.
    */
   public Object getObjectInstance (
         Object obj,
         Name name,  //NOTE: name needs to be implemented
         Context nameCtx,  //NOTE: name needs to be implemented
         Hashtable props)
      throws Exception
   {
      try
      {
         // if the object is a reference, we are going to assume that
         //   we can pull a server name and file system path out of it
         // the file system path is a name that can be passed to lookup()
         //   on the FileSystemInitialDirContext class
         if (obj instanceof Reference)
         {
            Reference ref = (Reference) obj;
            String serverPathStr;
            String serverName;
            String path;

            // get the server name, path combo
            serverPathStr = (String) ref.get (
                  ReferenceFactoryImpl.refAddrName).
                  getContent ();

            // treat it like a composite name
            Name serverPathCombo = new CompositeName (serverPathStr);

            // 1st component is server, 2nd component is full path
            serverName = serverPathCombo.get (0);
            path = serverPathCombo.get (1);

            // call the method below to actually create the FS context
            return (ContextFactoryImpl.getObjectInstance (serverName, path,
                  props));
         }

         if (obj instanceof FileSystemInitialDirContext |
             obj instanceof DirEntryDirContext)
            // then just return the context
            return (obj);

         return (null);
      }
      // could be thrown if the specified refAddr doesn't exist in
      //   the Reference passed in
      catch (Exception e)
      {
         return null;
      }
   }

   /**
    * Creates a context in the file system naming system using a server
    * name and a relative path.
    *
    * @param      serverName     A valid NetWare server name.
    * @param      path           A valid path to file system sub-context.
    *                            The path must be specified in JNDI name
    *                            format that is valid to the JNDI file
    *                            system initial context.
    * @param      env            Environment that is to be passed to
    *                            the newly constructed context.
    * @return                    JNDI context that is accessible in the
    *                            file system naming system.  If an exception
    *                            is thrown while creating this context,
    *                            null is returned.
    * @exception  Exception      Whan any other error occurs restoring
    *                            a context from reference information.
    * @exception  NSIException   When an error occurs attaching to the
    *                            specified server.
    * @exception NamingException When aied object relative to the file
    *                            system initial context.
    */
   public static Object getObjectInstance (String serverName, String path,
         Hashtable env)
      throws Exception
   {
      FileSystemInitialDirContext fsCtx =
            new FileSystemInitialDirContext(serverName, env);

      Object obj = fsCtx;

      if (path != null && path.length () > 0)
         obj = fsCtx.lookup (path);

      return (obj);
   }

   /**
    * Creates a context in the file system naming system using a server
    * name path.
    *
    * @param      serverName     A valid NetWare server name.
    * @param      path           A valid path to file system sub-context.
    *                            The path must be specified in JNDI name
    *                            format that is valid to the JNDI file
    *                            system initial context.
    * @param      env            Environment that is to be passed to
    *                            the newly constructed context.
    * @return                    JNDI context that is accessible in the
    *                            file system naming system.  If an exception
    *                            is thrown while creating this context,
    *                            null is returned.
    * @exception  Exception      Whan any other error occurs restoring
    *                            a context from reference information.
    * @exception  NSIException   When an error occurs attaching to the
    *                            specified server.
    * @exception NamingException When aied object relative to the file
    *                            system initial context.
    */
   public static DirContext getContextInstance(
      DirContext parent,
      String atomicName,   
      FSEnvironment environment,
      int type)
      throws NamingException
   {
      DirContext obj = null;
      switch (type)
      {
         case CREATE_VOLUME_CONTEXT:
            obj = new VolumeDirContext(environment);
            break;
            
         case CREATE_DIR_CONTEXT:
            obj = new DirectoryDirContext(
                        (DirectoryDirContext) parent, 
                        atomicName, 
                        environment);
            break;
            
         case CREATE_FILE_CONTEXT:
            obj = new FileDirContext(
                        (DirectoryDirContext) parent, 
                        atomicName, 
                        environment);
            break;

         case CREATE_SCHEMA_CONTEXT:
            obj = new Schema(environment);
            break;

         case CREATE_SCHEMA_CLASSDEF_CONTEXT:

            int schemaNodeType = -1;

            if (parent instanceof FileSystemInitialDirContext)
               schemaNodeType = SchemaClassDef.INITIAL_CLASSDEF;

            if (parent instanceof VolumeDirContext)
               schemaNodeType = SchemaClassDef.VOLDIR_CLASSDEF;

            if (parent instanceof DirectoryDirContext)
               schemaNodeType = SchemaClassDef.DIRECTORY_CLASSDEF;

            if (parent instanceof FileDirContext)
               schemaNodeType = SchemaClassDef.FILE_CLASSDEF;

            if (schemaNodeType == -1)
            {
               RuntimeException re = new IllegalArgumentException();
               NamingException ne = new NamingException();
               ne.setRootCause(re);
               throw ne;
            }

            obj = new SchemaClassDef(schemaNodeType, environment);
            break;

         case CREATE_SCHEMA_ATTRDEF_CONTEXT:
            obj = new SchemaAttrDef(environment);
            break;

         case CREATE_SCHEMA_SYNTAX_CONTEXT:
            obj = new SchemaSyntaxDef(environment);
            break;

         default:
            throw new IllegalArgumentException("" + type);
      }
      return obj;
   }
}
