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

  $Archive: /njcl_v2/src/com/novell/utility/naming/directory/StaticSchemaContext.java $
  $Revision: 4 $
  $Modtime: 10/04/99 9:50a $
 
  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.utility.naming.directory;


import java.util.*;

import javax.naming.*;

import javax.naming.directory.*;

import com.novell.utility.naming.FlatNameParser;


/**@internal
 * Schema context for an abstract system (intended to be subclassed).
 *
 * <p>This is the root schema DirContext that is returned from
 * DSCotnext.getSchema methods. It can also be subclassed to provide the
 * class definitions class.
 * </p>
 *
 * <p>See com.novell.service.bindery.naming.BinderySchemaContext for an example of how
 * to subclass this class for the schema object.
 * </p>
 *
 * <p>See com.novell.service.bindery.naming.BinderySchemaClassDefsContext for an
 * example of how to subclass this class for the class definitions object.
 * </p>
 */
public class StaticSchemaContext implements DirContext
{
   private static NameParser flatNameParser = new FlatNameParser ();
   protected NameParser nameParser = flatNameParser;

   protected String distinguishedName;

   protected Properties environment = new Properties ();

   // Two variables setup from parallel arrays during initBindingsAndPairs ().
   // These two variables manage and control this object's state.
   protected NameClassPair childNameClassPairs [];
   protected Binding childBindings [];

   /**
    *
    */
   public StaticSchemaContext (
         String name)
   {
      distinguishedName = name;
   }

   /**
    *
    */
   public StaticSchemaContext (
         String name,
         Binding[] bindings)
   {
      distinguishedName = name;
      childNameClassPairs = bindings;
      childBindings = bindings;
   }

   /**
    * Allows a subclass to reuse the construction of the arrays for
    * NameClassPair(s) and Binding(s).
    *
    * @param   names             (in) Custom names list.
    * @param   classes           (in) Custom classes list.
    * @param   objects           (in) Custom objects list.
    */
   public void initBindingsAndPairs (
         String childNames[],
         String childClasses[],
         Object childObjects[])
   {
      // Initialize the child NameClassPair and Binding arrays
      childNameClassPairs = new NameClassPair [childNames.length];
      childBindings = new Binding [childNames.length];
      for (int i = 0; i < childNames.length; i++)
      {
         childNameClassPairs [i] =
               new NameClassPair (
                       childNames[i],
                       ((i < childClasses.length) ?
                       childClasses[i] : "null"));
         childBindings [i] = new Binding (
                                    childNames[i],
                                    (i < childObjects.length) ?
                                    childObjects[i] : null);
      }
   } // initBindingsAndPairs ()

   // ******************** Context Interface ********************

   /** @internal
    *
    */
   public String getNameInNamespace ()
      throws NamingException
   {
      return (distinguishedName);
   }

   public Object lookup (
         String name)
      throws NamingException
   {  // Use the Name form of this method
      return (lookup (new CompositeName (name)));
   }
   public Object lookup (
         Name name)
      throws NamingException
   {
      if (name == null || name.size () == 0)
      {  // The caller wants THIS context
         return (this);
      }
      else
      {  // The caller wants a subordinate context
         String firstComponent = name.get (0);
         for (int i = 0; i < childNameClassPairs.length; i++)
         {
            if (firstComponent.equals (childNameClassPairs[i].getName ()))
            {
               Object resolvedObj = childBindings [i].getObject ();

               if (name.size () > 1)
               {
                  NameNotFoundException nnfe = new NameNotFoundException();
                  nnfe.setResolvedName( new CompositeName(firstComponent) );
                  nnfe.setRemainingName( name.getSuffix (1) );
                  nnfe.setResolvedObj( resolvedObj );
                  throw( nnfe );
               }
         
               return (resolvedObj);
            }
         }
         NameNotFoundException nnfe = new NameNotFoundException();
         nnfe.setResolvedName( new CompositeName() );
         nnfe.setRemainingName( name );
         nnfe.setResolvedObj( this );
         throw( nnfe );
      }
   }
   public void bind (
         String name,
         Object obj)
      throws NamingException
   {  // The default is a non-modifiable schema so dont support this method
      throw new OperationNotSupportedException();
   }
   public void bind (
         Name name,
         Object obj)
      throws NamingException
   {  // The default is a non-modifiable schema so dont support this method
      throw new OperationNotSupportedException();
   }
   public void rebind (
         String name,
         Object obj)
      throws NamingException
   {  // The default is a non-modifiable schema so dont support this method
      throw new OperationNotSupportedException();
   }
   public void rebind (
         Name name,
         Object obj)
      throws NamingException
   {  // The default is a non-modifiable schema so dont support this method
      throw new OperationNotSupportedException();
   }
   public void unbind (
         String name)
      throws NamingException
   {  // The default is a non-modifiable schema so dont support this method
      throw new OperationNotSupportedException();
   }
   public void unbind (
         Name name)
      throws NamingException
   {  // The default is a non-modifiable schema so dont support this method
      throw new OperationNotSupportedException();
   }
   public void rename (
         String oldName,
         String newName)
      throws NamingException
   {  // The default is a non-modifiable schema so dont support this method
      throw new OperationNotSupportedException();
   }
   public void rename (
         Name oldName,
         Name newName)
      throws NamingException
   {  // The default is a non-modifiable schema so dont support this method
      throw new OperationNotSupportedException();
   }
   public NamingEnumeration list (
         String name)
      throws NamingException
   {  // Use the Name form of this method
      return (list (new CompositeName (name)));
   }
   public NamingEnumeration list (
         Name name)
      throws NamingException
   {
      if (name == null || name.size () == 0)
      {  // The caller wants the list for THIS context
         return (new NameClassPairEnumerator (childNameClassPairs));
      }
      else
      {  // The lookup will throw an exception so we don't need to
         Object obj = lookup (name);
         if (obj instanceof Context)
            return (((Context) obj).list (""));
         else
         {
            NotContextException nce = new NotContextException();
            nce.setResolvedName( new CompositeName() );
            nce.setRemainingName( name );
            nce.setResolvedObj( obj );
            throw( nce );
         }
      }
   }
   public NamingEnumeration listBindings (
         String name)
      throws NamingException
   {  // Use the Name form of this method
      return (listBindings (new CompositeName (name)));
   }
   public NamingEnumeration listBindings (
         Name name)
      throws NamingException
   {
      if (name == null || name.size () == 0)
      {  // The caller wants the list for THIS context
         return (new BindingEnumerator (childBindings));
      }
      else
      {  // The lookup will throw an exception so we don't need to
         Object obj = lookup (name);
         if (obj instanceof Context)
            return (((Context) obj).listBindings (""));
         else
         {
            NotContextException nce = new NotContextException();
            nce.setResolvedName( new CompositeName() );
            nce.setRemainingName( name );
            nce.setResolvedObj( obj );
            throw( nce );
         }
      }
   }
   public void destroySubcontext (
         String name)
      throws NamingException
   {  // The default is a non-modifiable schema so dont support this method
      throw new OperationNotSupportedException();
   }
   public void destroySubcontext (
         Name name)
      throws NamingException
   {  // The default is a non-modifiable schema so dont support this method
      throw new OperationNotSupportedException();
   }
   public Context createSubcontext (
         String name)
      throws NamingException
   {  // The default is a non-modifiable schema so dont support this method
      throw new OperationNotSupportedException();
   }
   public Context createSubcontext (
         Name name)
      throws NamingException
   {  // The default is a non-modifiable schema so dont support this method
      throw new OperationNotSupportedException();
   }
   public Object lookupLink (
         String name)
      throws NamingException
   {  // Use the Name form of this method
      return (lookupLink (new CompositeName (name)));
   }
   public Object lookupLink (
         Name name)
      throws NamingException
   {  // We just use lookup for lookupLink
      return (lookup (name));
   }
   public NameParser getNameParser (
         String name)
      throws NamingException
   {  // Use the Name form of this method
      return (getNameParser (new CompositeName (name)));
   }
   public NameParser getNameParser (
         Name name)
      throws NamingException
   {
      if (name == null || name.size () == 0)
      {  // The caller wants the list for THIS context
         return (nameParser);
      }
      else
      {  // The lookup will throw an exception so we don't need to
         Object obj = lookup (name);
         if (obj instanceof Context)
            return (((Context) obj).getNameParser (""));
         else
         {
            NotContextException nce = new NotContextException();
            nce.setResolvedName( new CompositeName() );
            nce.setRemainingName( name );
            nce.setResolvedObj( obj );
            throw( nce );
         }
      }
   }

   public Object addToEnvironment (
         String str,
         Object obj ) 
      throws NamingException
   {
//NOTE: need implementation here - I think we need to do a property merge
throw new OperationNotSupportedException();
   }

   public Hashtable getEnvironment ()
      throws NamingException
   {
      return (environment);
   }

   public Object removeFromEnvironment (
         String s) 
      throws NamingException
   {
//NOTE: need implementation here - I think we need to do a property merge
throw new OperationNotSupportedException();
   }

   public String composeName (
         String name, 
         String prefix)
      throws NamingException 
   {
//NOTE: need implementation here - I think we need to do a compose name
throw new OperationNotSupportedException();
   }

   public Name composeName (
         Name name, 
         Name prefix)
      throws NamingException 
   {
//NOTE: need implementation here - I think we need to do a compose name
throw new OperationNotSupportedException();
   }

   public void close ()
      throws NamingException
   {
      //... no close necessary
   }

   /* ***********************************************************************
    * DirContext Methods
    ************************************************************************/
   public Attributes getAttributes (
         String name)
      throws NamingException
   {  // Use the Name form of this method
      return (getAttributes (new CompositeName (name)));
   }
   public Attributes getAttributes (
         Name name)
      throws NamingException
   {  // Use the attribute id form of this method
      return (getAttributes (name, (String[]) null));
   }
   public Attributes getAttributes (
         String name,
         String[] attrIds)
      throws NamingException
   {  // Use the Name form of this method
      return (getAttributes (new CompositeName (name), attrIds));
   }
   /**
    * This is the only getAttribute method a subclass must override
    */
   public Attributes getAttributes (
         Name name,
         String[] attrIds)
      throws NamingException
   {  // No default support for meta-data on the schema
      throw new OperationNotSupportedException();
   }
   public void modifyAttributes (
         String name,
         int mod_op,
         Attributes attrs)
      throws NamingException
   {
      throw new OperationNotSupportedException();
   }
   public void modifyAttributes (
         Name name,
         int mod_op,
         Attributes attrs)
      throws NamingException
   {  // The default is a non-modifiable schema so dont support this method
      throw new OperationNotSupportedException();
   }
   public void modifyAttributes (
         String name,
         ModificationItem[] mods)
      throws NamingException
   {  // The default is a non-modifiable schema so dont support this method
      throw new OperationNotSupportedException();
   }
   public void modifyAttributes (
         Name name,
         ModificationItem[] mods)
      throws NamingException
   {  // The default is a non-modifiable schema so dont support this method
      throw new OperationNotSupportedException();
   }
   public void bind (
         String name,
         Object obj,
         Attributes attrs)
      throws NamingException
   {  // The default is a non-modifiable schema so dont support this method
      throw new OperationNotSupportedException();
   }
   public void bind (
         Name name,
         Object obj,
         Attributes attrs)
      throws NamingException
   {  // The default is a non-modifiable schema so dont support this method
      throw new OperationNotSupportedException();
   }
   public void rebind (
         String name,
         Object obj,
         Attributes attrs)
      throws NamingException
   {  // The default is a non-modifiable schema so dont support this method
      throw new OperationNotSupportedException();
   }
   public void rebind (
         Name name,
         Object obj,
         Attributes attrs)
      throws NamingException
   {  // The default is a non-modifiable schema so dont support this method
      throw new OperationNotSupportedException();
   }
   public DirContext createSubcontext (
         String name, 
         Attributes attrs)
      throws NamingException
   {  // The default is a non-modifiable schema so dont support this method
      throw new OperationNotSupportedException();
   }
   public DirContext createSubcontext (
         Name name, 
         Attributes attrs)
      throws NamingException
   {  // The default is a non-modifiable schema so dont support this method
      throw new OperationNotSupportedException();
   }
   public DirContext getSchema (
         String name)
      throws NamingException
   {  // No default support for meta-data on the schema
      throw new OperationNotSupportedException();
   }
   public DirContext getSchema (
         Name name)
      throws NamingException
   {  // No default support for meta-data on the schema
      throw new OperationNotSupportedException();
   }
   public DirContext getSchemaClassDefinition (
         String name)
      throws NamingException
   {  // No default support for meta-data on the schema
      throw new OperationNotSupportedException();
   }
   public DirContext getSchemaClassDefinition (
         Name name)
      throws NamingException
   {  // No default support for meta-data on the schema
      throw new OperationNotSupportedException();
   }
   /* *************** searches *************** */
   public NamingEnumeration search (
         String name,
         Attributes matchingAttributes)
      throws NamingException
   {  // We're not supporting searching the schema
      throw new OperationNotSupportedException();
   }
   public NamingEnumeration search (
         Name name,
         Attributes matchingAttributes)
      throws NamingException
   {  // We're not supporting searching the schema
      throw new OperationNotSupportedException();
   }
   public NamingEnumeration search (
         String name, 
         Attributes matchingAttributes,
         String[] attributesToReturn)
      throws NamingException
   {  // We're not supporting searching the schema
      throw new OperationNotSupportedException();
   }
   public NamingEnumeration search (
         Name name, 
         Attributes matchingAttributes,
         String[] attributesToReturn)
      throws NamingException
   {  // We're not supporting searching the schema
      throw new OperationNotSupportedException();
   }
   public NamingEnumeration search (
         String name, 
         String filter,
         SearchControls cons)
      throws NamingException
   {  // We're not supporting searching the schema
      throw new OperationNotSupportedException();
   }
   public NamingEnumeration search (
         Name name, 
         String filter,
         SearchControls cons)
      throws NamingException
   {  // We're not supporting searching the schema
      throw new OperationNotSupportedException();
   }
   public NamingEnumeration search (
         String name,
         String filterExpr,
         Object[] filterArgs,
         SearchControls cons)
      throws NamingException
   {  // We're not supporting searching the schema
      throw new OperationNotSupportedException();
   }
   public NamingEnumeration search (
         Name name,
         String filterExpr,
         Object[] filterArgs,
         SearchControls cons)
      throws NamingException
   {  // We're not supporting searching the schema
      throw new OperationNotSupportedException();
   }


   /* **************************************************************************
    * class NameClassPairEnumerator
    ***************************************************************************/

   class NameClassPairEnumerator implements NamingEnumeration
   {
      private int index = 0;
      private NameClassPair ncPairArray[];

      public NameClassPairEnumerator (
            NameClassPair[] ncPairArray)
      {
         this.ncPairArray = ncPairArray;
      }

      public boolean hasMoreElements ()
      {
         return (index < ncPairArray.length);
      }

      public boolean hasMore ()
         throws NamingException
      {
         return (hasMoreElements ());
      }

      public Object nextElement ()
      {
         try
         {
            return (next ());
         }
         catch (NamingException e)
         {
            throw (new NoSuchElementException ());
         }
      }

      public Object next ()
         throws NamingException
      {
         if (index >= ncPairArray.length)
            throw new NoSuchElementException ();
         return (ncPairArray[index++]);
      }

      /**
       *
       */
      public void close ()
         throws NamingException
      {
      }

   } /* NameClassPairEnumerator */

   /* **************************************************************************
    * class BindingEnumerator
    ***************************************************************************/

   class BindingEnumerator implements NamingEnumeration
   {
      private int index = 0;
      private Binding bindingArray[];

      public BindingEnumerator (
            Binding bindingArray[])
      {
         this.bindingArray = bindingArray;
      }


      public boolean hasMoreElements()
      {
         return (index < bindingArray.length);
      }

      public boolean hasMore ()
         throws NamingException
      {
         return (hasMoreElements ());
      }

      public Object nextElement()
      {
         try
         {
            return (next ());
         }
         catch (NamingException e)
         {
            throw (new NoSuchElementException ());
         }
      }

      public Object next()
         throws NamingException
      {
         if (index >= bindingArray.length)
            throw new NoSuchElementException ();
         return (bindingArray [index++]);
      }

      /**
       *
       */
      public void close ()
         throws NamingException
      {
      }

   } /* BindingEnumerator */


} /* StaticSchemaContext */


