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

  $Archive: /njcl_v2/src/com/novell/service/nds/naming/net/NetSchemaDirContext.java $
  $Revision: 11 $
  $Modtime: 1/28/00 12:46p $
 
  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.nds.naming.net;


import java.util.*;

import javax.naming.*;
import javax.naming.CompositeName;
import javax.naming.directory.*;

import com.sun.jndi.toolkit.ctx.*;

import com.novell.service.jncp.NSIException;

import com.novell.service.nds.*;
import com.novell.service.nds.naming.*;
import com.novell.service.nds.ldap.LdapAttributeValueFactory;

import com.novell.service.rfc1960.*;

import com.novell.service.jncpv2.net.NetService;

import com.novell.utility.naming.Environment;
import com.novell.utility.naming.directory.NAttributes;
import com.novell.utility.naming.directory.SearchEnumerator;
import com.novell.utility.naming.directory.SearchFilterFactory;
import com.novell.utility.naming.spi.ContextFactory;


/** @internal
 * This class contains common code for all schema contexts.
 */
public abstract class NetSchemaDirContext
   extends AtomicDirContext
   implements NdsDataAccessor, SchemaDirContextWrappable
{
   protected static ContextFactory factory = new SchemaContextFactory ();
   protected static NameParser nameParser = new NdsNameParser ();

   private final String distinguishedName;
   private final String baseClass;
//   protected Name name;
//   protected String atomicName;
   protected NetEnvironment environment;


   /**
    * Constructor for SchemaAtomicDirContext method
    *
    * @param objectName    Distinguished name of this object
    * @param baseClass     NDS class name
    * @param environment properties to be set in this objects environment
    */
   protected NetSchemaDirContext (
         String objectName,
         String baseClass,
         NetEnvironment environment)
      throws NamingException
   {
      this.distinguishedName = objectName;
//      this.name = nameParser.parse (objectName);
      this.baseClass = baseClass;
//      this.atomicName = name.get (name.size () - 1);
      this.environment = (NetEnvironment) environment.clone ();

   } /* SchemaAtomicDirContext () */


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

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

   /**
    *
    */
   public Object addToEnvironment (
         String propName,
         Object propVal)
      throws NamingException
   {
      return (environment.addToEnvironment (propName, propVal));

   } /* addToEnvironment () */

   /**
    *
    */
   public Object removeFromEnvironment (
         String propName)
      throws NamingException
   {
      return (environment.removeFromEnvironment (propName));

   } /* removeFromEnvironment () */

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

   /* ***********************************************************************
    * Atomic Toolkit methods
    ************************************************************************/

   /**
    *
    */
   protected StringHeadTail c_parseComponent (
         String inputName,
         Continuation cont)
      throws NamingException
   {
      try
      {
         CompoundName n = (CompoundName)nameParser.parse (inputName);
         if (n.isEmpty () || 1 == n.size ())
         {
            return new StringHeadTail (inputName, null);
         }
         else
         {
            return new StringHeadTail (
                        n.getPrefix (1).toString (),
                        n.getSuffix (1).toString ());
         }
      }
      catch (NamingException e)
      {
         throw cont.fillInException (e);
      }
   }

   /* ***********************************************************************
    * protected Toolkit Context methods
    ************************************************************************/

   /**
    * Generic lookup.  This uses the name to return the correct
    * schema context.
    */
   protected Object a_lookup (
         String name,
         Continuation cont)
      throws NamingException
   {
      Object object;

      if (isEmpty (name))
      {
         object = getInstance ();
      }
      else
      {
         int index;
         Name target;

         if ((index = name.indexOf ('=')) > 0)
         {
            name = name.substring (index + 1);
         }

         target = nameParser.parse (name);
         target.addAll (0, getNameInstance ());

         try
         {
            object = factory.getContextInstance (
                                 target.toString (),
                                 environment);
         }
         catch (NamingException e)
         {
            cont.setError (this, name);
            throw cont.fillInException (e);
         }
      }
      cont.setSuccess ();
      return (object);

   } /* a_lookup () */

   /**
    * There are no links in the schema
    */
   protected Object a_lookupLink (
         String name,
         Continuation cont)
      throws NamingException
   {
      return a_lookup (name, cont);
   }

   /**
    * Call subclasses implementation of abstract
    * schema_list
    */
   protected NamingEnumeration a_list (
         Continuation cont)
      throws NamingException
   {
      return schema_list (cont);
   }

   /**
    * Call subclasses implementation of abstract
    * schema_listBindings
    */
   protected NamingEnumeration a_listBindings (
         Continuation cont)
      throws NamingException
   {
      return schema_listBindings (cont);
   }

   /**
    * Call subclasses implementation of abstract
    * schema_bind
    */
   protected void a_bind (
         String name,
         Object obj,
         Continuation cont)
      throws NamingException
   {
      schema_bind (name, obj, cont);
   }

   /**
    * Call subclasses implementation of abstract
    * schema_rebind
    */
   protected void a_rebind (
         String name,
         Object obj,
         Continuation cont)
      throws NamingException
   {
      schema_rebind (name, obj, cont);
   }

   /**
    * Call subclasses implementation of abstract
    * schema_unbind
    */
   protected void a_unbind (
         String name,
         Continuation cont)
      throws NamingException
   {
      schema_unbind (name, cont);
   }

   /**
    * Call subclasses implementation of abstract
    * schema_rename
    */
   protected void a_rename (
         String oldName,
         Name newName,
         Continuation cont)
      throws NamingException
   {
      schema_rename (oldName, newName, cont);
   }

   /**
    * Call subclasses implementation of abstract
    * schema_destroySubcontext
    */
   protected void a_destroySubcontext (
         String name,
         Continuation cont)
      throws NamingException
   {
      schema_destroySubcontext (name, cont);
   }

   /**
    * Call subclasses implementation of abstract
    * schema_createSubcontext
    */
   protected Context a_createSubcontext (
         String name,
         Continuation cont)
      throws NamingException
   {
      return schema_createSubcontext (name, cont);
   }

   /**
    *
    */
   protected NameParser a_getNameParser (
         Continuation cont)
      throws NamingException
   {
      cont.setSuccess ();
      return nameParser;
   }

   /**
    * This should work whether the Name's are Compound or Composite.
    * If prefix is CompoundName, its nameparser is used to append.
    */
   public Name composeName (
         Name name,
         Name prefix)
      throws NamingException
   {
      int preCount = prefix.size ();

      // Since there is no federation from this point on, we'll just
      // glue the atomic ends together.

      if (preCount == 0)
      {
         return name;
      }

      if (name.size () == 0)
      {
         return prefix;
      }

      Name ret = (Name)prefix.clone ();

      // Get the last part of the prefix as a CompoundName
      Name suf = nameParser.parse (ret.get (preCount - 1));

      // Append the first part of the name
      suf.addAll (nameParser.parse (name.get (0)));

      // Replace end of prefix with new name
      ret.remove (preCount - 1);
      ret.add (suf.toString ());

      // Append remainder from name to pre
      ret.addAll (name.getSuffix (1));

      return ret;
   }

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

   /* ***********************************************************************
    * protected Toolkit DirContext methods
    ************************************************************************/

   /**
    * No schema schema's, not supported
    */
   protected DirContext a_getSchema (
         Continuation cont)
      throws NamingException
   {
      cont.setError (this, "");
      throw cont.fillInException (new OperationNotSupportedException ());
   }

   /**
    * No schema schema's, not supported
    */
   protected DirContext a_getSchemaClassDefinition (
         Continuation cont)
      throws NamingException
   {
      cont.setError (this, "");
      throw cont.fillInException (new OperationNotSupportedException ());
   }

   /**
    * Generic getAttributes. This relies on the implementation specific
    * getAttrItems method.
    */
   protected Attributes a_getAttributes (
         String name,
         String[] attrIDs,
         Continuation cont)
      throws NamingException
   {
      if (! isEmpty (name))
      {
         resolveNext (name, cont);
         return null;
      }

      Attributes ret = new NAttributes (true);
      Hashtable attrItems = getAttrItems ();

      if (null == attrIDs)
      {
         // Add all attributes
         Enumeration e = attrItems.keys ();
         while (e.hasMoreElements ())
         {
            ret.put ((Attribute) attrItems.get (e.nextElement ()));
         }
      }
      else
      {
         // Add all matching attributes
         for (int i = 0; i < attrIDs.length; i++)
         {
            // Is it in the set of attrItems?
            Attribute attr = (Attribute) attrItems.get (
                                             attrIDs[i].toUpperCase());
            if (attr != null)
            {
               ret.put (attr);
            }
         }
      }
      return ret;
   }

   /**
    * Handle name or call subclasses implementation of abstract
    * schema_modifyAttributes.
    */
   protected void a_modifyAttributes (
         String name,
         int mod_op,
         Attributes attrs,
         Continuation cont)
      throws NamingException
   {
      if (isEmpty (name))
      {
         schema_modifyAttributes (mod_op, attrs, cont);
      }
      else
      {
         resolveNext (name, cont);
      }
   }

   /**
    * Handle name or call subclasses implementation of abstract
    * schema_modifyAttributes
    */
   protected void a_modifyAttributes (
         String name,
         ModificationItem[] mods,
         Continuation cont)
      throws NamingException
   {
      if (isEmpty (name))
      {
         schema_modifyAttributes (mods, cont);
      }
      else
      {
         resolveNext (name, cont);
      }
   }

   /**
    * Call subclasses implementation of abstract
    * schema_bind
    */
   protected void a_bind (
         String name,
         Object obj,
         Attributes attrs,
         Continuation cont)
      throws NamingException
   {
      schema_bind (name, obj, attrs, cont);
   }

   /**
    * Call subclasses implementation of abstract
    * schema_rebind
    */
   protected void a_rebind (
         String name,
         Object obj,
         Attributes attrs,
         Continuation cont)
      throws NamingException
   {
      schema_rebind (name, obj, attrs, cont);
   }

   /**
    * Call subclasses implementation of abstract
    * schema_createSubContext
    */
   protected DirContext a_createSubcontext (
         String name,
         Attributes attrs,
         Continuation cont)
      throws NamingException
   {
      return schema_createSubcontext (name, attrs, cont);
   }

   /**
    * Generic search.  If there is a set of matchingAttrs, this converts
    * the attribute set in matchingAttrs into a
    * COM.novell.jndi.naming.directory.SearchFilter which is then
    * accessed in order to call the overloaded version of search that takes
    * a search filter string and array of arg's.
    * If matchingAttrs is empty, it returns itself and all subcontexts.
    */
   protected NamingEnumeration a_search (
         Attributes matchingAttrs,
         String[] returnAttrs,
         Continuation cont)
      throws NamingException
   {
      if (matchingAttrs == null || matchingAttrs.size () == 0)
      {
         // Return this object and all subcontexts.
         Vector searchResults = new Vector ();
/*
         // Add this object
         searchResults.addElement (new SearchResult (
                                          atomicName,
                                          getInstance (),
                                          a_getAttributes (
                                                "",
                                                returnAttrs,
                                                cont)));
*/
         // Add all bindings
         NamingEnumeration be = listBindings ("");
         while (be.hasMoreElements ())
         {
            // Get next binding
            Binding binding = (Binding)be.next ();
            DirContext dsCtx = (DirContext)binding.getObject ();

            // Get this binding's attrs
            Attributes attrs = dsCtx.getAttributes ("", returnAttrs);

            // Add this binding
            searchResults.addElement (new SearchResult (
                                          binding.getName (),
                                          binding.getClassName(),
                                          null, //dsCtx,
                                          attrs,
                                          true));
         }

         cont.setSuccess ();
         return new SearchEnumerator (searchResults);
      }
      else
      {
         // Valid attribute set.  Convert to filter and use filter to search
         SearchFilterFactory sf = new SearchFilterFactory (matchingAttrs);
         SearchControls constraints = new SearchControls ();
         constraints.setReturningAttributes (returnAttrs);
         return a_search (
            "",
            sf.getExpression (),
            sf.getArgs (),
            constraints,
            cont);
      }
   }

   /**
    * Generic search. This search will first examine this object, then
    * search all children.  This is a depth first search.
    */
   protected NamingEnumeration a_search (
         String name,
         String filterExpr,
         Object [] filterArgs,
         SearchControls cons,
         Continuation cont)
      throws NamingException
   {
      if (false == isEmpty (name))
      {
         resolveNext (name, cont);
         return null;
      }

      if (cons == null)
      {
         cons = new SearchControls ();
      }

      int timeLim = cons.getTimeLimit ();
      long timeEnd = 0;
      long timeLeft = 0;
      boolean timed = false;
      long countLim = cons.getCountLimit ();
      boolean sized = countLim == 0 ? false : true;
      int scope = cons.getSearchScope ();

      if (timeLim != 0)
      {
         timeEnd = System.currentTimeMillis () + timeLim;
         timed = true;
      }

      // Parse the filter expression.
      Rfc1960Parser ssp;
      try
      {
        ssp = new Rfc1960Parser (filterExpr);
      }
      catch (IllegalArgumentException e)
      {
         cont.setError (this, name);
         InvalidSearchFilterException ne =
               new InvalidSearchFilterException ();
         ne.setRootCause (e);
         throw cont.fillInException (ne);
      }

      // Search this context
      Vector searchResults = new Vector ();
      try
      {
         SearchResult sr = searchObject (
                              ssp,
                              cons,
                              filterArgs);
         if (sr != null)
         {
            searchResults.addElement (sr);
         }

         // Bail out if OBJECT_SCOPE
         if (scope == SearchControls.OBJECT_SCOPE)
         {
            return new SearchEnumerator (searchResults);
         }
      }
      catch (NamingException ne)
      {
         cont.setError (this, name);
         throw cont.fillInException (ne);
      }

      // Construct new constraints based on those passed in.
      // Change scope to OBJECT_SCOPE if ONELEVEL_SCOPE is passed in.
      SearchControls constraints = new SearchControls (
                                 scope == SearchControls.ONELEVEL_SCOPE ?
                                          SearchControls.OBJECT_SCOPE :
                                          scope,
                                 countLim,
                                 timeLim,
                                 cons.getReturningAttributes (),
                                 cons.getReturningObjFlag (),
                                 cons.getDerefLinkFlag ());

      // Search bindings.
      NamingEnumeration be = listBindings ("");
      while (be.hasMoreElements ())
      {
         // Check and update constraints.
         if (timed)
         {
            if ((timeLeft = (timeEnd - System.currentTimeMillis ())) <= 0)
            {
               // Time limit has been reached.  Bail out.
               break;
            }
            constraints.setTimeLimit ((int)timeLeft);
         }
         if (sized)
         {
            if (countLim <= 0)
            {
               // Count limit has been reached.  Bail out.
               break;
            }
            constraints.setCountLimit (countLim);
         }

         // Get next binding
         Binding binding = (Binding) be.next ();
         Object bindObj = binding.getObject();
         if (!(bindObj instanceof DirContext))
            continue;
            
         String bindingName = binding.getName();
         DirContext dsCtx = (DirContext)bindObj;

         NamingEnumeration se;
         try
         {
            // Search this binding and add all SearchResults to vector
            se = dsCtx.search ("", filterExpr, filterArgs, constraints);
         }
         catch (NamingException ne)
         {
            cont.setError (this, name);
            throw cont.fillInException (ne);
         }

         while (se.hasMoreElements ())
         {
            SearchResult sr = (SearchResult) se.next ();

            String newName = sr.getName();
            if (newName.length() == 0)
               newName = bindingName;
            else
               newName = dsCtx.composeName(
                                       newName,
                                       bindingName);

            sr.setName(newName);
/*
            // Create new SearchResult with modified name
            // (prepend binding name to returned name)
            SearchResult newSr = new SearchResult (
                                 newName,
                                 sr.getObject (),
                                 sr.getAttributes ());
*/
            searchResults.addElement (sr);

            // Reduce count limit.
            if (sized)
            {
               countLim--;
            }
         }
      }

      cont.setSuccess ();
      return (new SearchEnumerator (searchResults));
   }

   /**
    *
    */
   protected NamingEnumeration a_search (
         String name,
         String filter,
         SearchControls cons,
         Continuation cont)
      throws NamingException
   {
      SearchControls c = (cons == null ? new SearchControls() : cons);

      return a_search (name, filter, null, cons, cont);
   }


   /* ***********************************************************************
    * Utility methods
    ************************************************************************/

   protected Name components;

   /**
    *
    */
   protected synchronized Name getNameInstance ()
      throws NamingException
   {
      if (components == null)
      {
         components = nameParser.parse (distinguishedName);
      }
      return (components);

   } /* getNameInstance () */

   /**
    * Returns the ContextHandle associated with this Context.
    *
   protected int getContextHandle ()
      throws NamingException
   {
      return getSession ().getContextHandle ();

   } *  */

   /**
    * Returns the session associated with this Context.
    */
   protected NetService getService ()
      throws NamingException
   {
      return (environment.getService ());
   }

   /**
    * Returns the base class associated with this Context.
    */
   public String getBaseClass ()
      throws NSIException
   {
      return (baseClass);
   }

   /**
    *
    */
   public Environment getEnvironmentInstance ()
      throws NamingException
   {
      return (environment);
   }

   /**
    * Returns the distinguished name associated with this Context.
    */
   protected String getDistinguishedName ()
   {
      return distinguishedName;
   }

   /**
    * Returns an instance of this object through the factory
    */
   protected Object getInstance ()
      throws NamingException
   {
      return (factory.getContextInstance (
                           distinguishedName,
                           baseClass,
                           environment));
   }

   /**
    * This is called by methods that need to perform name resolution.
    * The name is looked up and the Continuation object is told to continue.
    */
   private void resolveNext (
         String name,
         Continuation cont)
      throws NamingException
   {
      Object obj = a_lookup (name, cont);
      if (null != obj)
      {
         cont.setContinue (obj, name, this, "");
      }
   }

   /**
    * Helper method for a_search
    *
    * <p>This method examines the current object
    * </p>
    *
    * @param ssp                 The search string parser to use for
    *                            obtaining the needed attribute id's, compare
    *                            operations and operands.
    *
    * @param returnAttrs         The attributes that should be returned
    *                            if this context matches.
    * @param filterArgs          Array that contains the
    *                            attribute values to compare on replacement.
    * @return                    SearchResult on match, null otherwise.
    * @exception                 NamingException
    *
    */
   private SearchResult searchObject (
         Rfc1960Parser ssp,
         SearchControls cons,
         Object [] filterArgs)
      throws NamingException
   {
      Attributes attrs;
      SearchStringComponent comp;
      NdsAttributeValue value;
//      SSComponentEnumerator sscenum;
      String[] returnAttrs = cons.getReturningAttributes ();

      try
      {
         // Get all the attributes for this context
         attrs = getAttributes ("");

         // Compare each search string
         while (ssp.hasMoreElements ())
         {
            boolean compared = false;

            // Get next SearchStringComponent from parser
            comp = ssp.next ();

            // Compare componenet to each value in attribute
            Attribute attr = attrs.get (comp.getAttributeId ());
            if (attr != null)
            {
               Enumeration values = attr.getAll ();
               while (values.hasMoreElements ())
               {
                  if ((compared = compareValue (
                              comp,
                              (NdsAttributeValue)values.nextElement (),
                              filterArgs)))
                  {
                     break;
                  }
               }
            }

            // Store result of call to compareValue in parser.
            // This will allow parser to perform early out logic.
            ssp.setCompareResult (comp, compared);
         }

         // Check parser to see if we can bail out yet.
         if (false == ssp.compared ())
         {
            return null;
         }
      }
      catch (InvalidSearchFilterException e)
      {
         // Problem with the search filter and replacement params
         throw e;
      }
      catch (NamingException e)
      {
         // Do nothing. Assume search not found and return
         return null;
      }

      if (null != returnAttrs)
      {
         // Replace full set of attrs with subset asked for
         attrs = getAttributes ("", returnAttrs);
      }
      // else they get the whole set of attributes for this context

      return new SearchResult (
                  "",
                  cons.getReturningObjFlag () ? getInstance () : null,
                  attrs,
                  true);
   }

   /**
    * Helper method for searchObject.  This method compares the value
    * specified in comp and filter to that in value.
    *
    * @param comp          The component to be compared
    *
    * @param value         The attributes value to compare against.
    *
    * @param filterArgs    An array that contains the
    *                      attribute values to compare.
    *
    * @return              true if the attribute values match.
    *
    */
   private boolean compareValue (
         SearchStringComponent comp,
         NdsAttributeValue value,
         Object [] filterArgs)
      throws NamingException
   {
      boolean compared = false;
      int operationType = comp.getOperationType ();
      NdsAttributeValue operand;

      // See if value supports the operation
      if (false == value.supportsMatchingRules (
            SearchStringComponent.EQUALS == operationType ?
               NdsAttributeValue.equality : (
            SearchStringComponent.APPROXIMATE == operationType ?
               NdsAttributeValue.approximate : (
            SearchStringComponent.GREATER_OR_EQUAL == operationType ?
               NdsAttributeValue.ordering : (
            SearchStringComponent.LESS_OR_EQUAL == operationType ?
               NdsAttributeValue.ordering : (
            SearchStringComponent.SUBSTRING == operationType ?
               NdsAttributeValue.substrings :
               NdsAttributeValue.none))))))
      {
         // Can't perform specified operation
         return false;
      }

      // Get operand as an NdsAttributeValue
      if (comp.operandReplacement ())
      {
         try
         {
            // Extract from array if using replacement param's
            operand = (NdsAttributeValue)
                  filterArgs [comp.getReplacementIndex ()];
         }
         catch (ArrayIndexOutOfBoundsException e)
         {
            NamingException ne = new InvalidSearchFilterException ();
            ne.setRootCause (e);
            throw ne;
         }
         catch (ClassCastException e)
         {
            // Wrong type in filterArgs
            return false;
         }
      }
      else
      {
         try
         {
            // Create from string
            operand = new LdapAttributeValueFactory ().createValue (
                                                value.getNdsSyntaxId (),
                                                comp.getOperand ());
         }
         catch (Exception e)
         {
            // Couldn't create value
            return false;
         }
      }

      try
      {
         // Compare attributes
         switch (operationType)
         {
            case SearchStringComponent.SUBSTRING:
            case SearchStringComponent.EQUALS:
               compared = value.equals (operand);
               break;

            case SearchStringComponent.APPROXIMATE:
               compared = value.approximate (operand);
               break;

            case SearchStringComponent.GREATER_OR_EQUAL:
               compared = 0 <= value.compareTo (operand);
               break;

            case SearchStringComponent.LESS_OR_EQUAL:
               compared = 0 >= value.compareTo (operand);
               break;

            case SearchStringComponent.PRESENT:
               compared = true;
               break;

            default:
               // Anything other than values above is not supported
               // (Should never get here)
               return false;
         }
      }
      catch (Exception e)
      {
         // Couldn't compare values
         return false;
      }

      return compared;
   }

   /* ***********************************************************************
    * Abstract methods
    ************************************************************************/

   /**
    * Same as a_list
    */
   protected abstract NamingEnumeration schema_list (
         Continuation cont)
      throws NamingException;

   /**
    * Same as a_listBindings
    */
   protected abstract NamingEnumeration schema_listBindings (
         Continuation cont)
      throws NamingException;

   /**
    * Same as a_bind
    */
   protected abstract void schema_bind (
         String name,
         Object obj,
         Continuation cont)
      throws NamingException;

   /**
    * Same as a_rebind
    */
   protected abstract void schema_rebind (
         String name,
         Object obj,
         Continuation cont)
      throws NamingException;

   /**
    * Same as a_unbind
    */
   protected abstract void schema_unbind (
         String name,
         Continuation cont)
      throws NamingException;

   /**
    * Same as a_rename
    */
   protected abstract void schema_rename (
         String oldName,
         Name newName,
         Continuation cont)
      throws NamingException;

   /**
    * Same as a_destroySubcontext
    */
   protected abstract void schema_destroySubcontext (
         String name,
         Continuation cont)
      throws NamingException;

   /**
    * Same as a_createSubcontext
    */
   protected abstract Context schema_createSubcontext (
         String name,
         Continuation cont)
      throws NamingException;

   /**
    * Same as a_modifyAttributes except thre is no name param which is
    * not needed.
    */
   protected abstract void schema_modifyAttributes (
         int mod_op,
         Attributes attrs,
         Continuation cont)
      throws NamingException;

   /**
    * Same as a_modifyAttributes except thre is no name param which is
    * not needed.
    */
   protected abstract void schema_modifyAttributes (
         ModificationItem[] mods,
         Continuation cont)
      throws NamingException;

   /**
    * Same as a_bind
    */
   protected abstract void schema_bind (
         String name,
         Object obj,
         Attributes attrs,
         Continuation cont)
      throws NamingException;

   /**
    * Same as a_rebind
    */
   protected abstract void schema_rebind (
         String name,
         Object obj,
         Attributes attrs,
         Continuation cont)
      throws NamingException;

   /**
    * Same as a_createSubcontext
    */
   protected abstract DirContext schema_createSubcontext (
         String name,
         Attributes attrs,
         Continuation cont)
      throws NamingException;

   /**
    * Returns a Hashtable filled with the attributes of this context
    * This is called by a_getAttributes
    */
   protected abstract Hashtable getAttrItems () throws NamingException;

} /* SchemaAtomicDirContext */

