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

  $Archive: /njcl_v2rmi/src/com/novell/service/nds/naming/net/NetAttributeDefinitionsDirContext.java $
  $Revision: 13 $
  $Modtime: 1/05/01 3:59p $
 
  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.rmi.RemoteException;
import java.util.*;

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

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

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

import com.novell.service.jncp.*;

import com.novell.service.session.SessionException;
import com.novell.service.jncpv2r.net.*;

import com.novell.utility.naming.spi.ContextFactory;


/** @internal
 * This class is bound to the root of the schema tree and has bindings
 * to all NDS Attribute definitions.
 *
 * @see JNDI documentation section 5.2.4 Schema
 */
public class NetAttributeDefinitionsDirContext
      extends NetSchemaContainerDirContext
{
   private static NdsNamingExceptionFactory exceptionFactory =
       new NdsNamingExceptionFactory ();

   /**
    * Constructor.
    *
    * @param objectName    Distinguished name of this object
    * @param baseClass     NDS class name
    * @param environment properties to be set in this objects environment
    */
   protected NetAttributeDefinitionsDirContext (
         String objectName,
         String baseClass,
         NetEnvironment environment)
      throws NamingException
   {
      super (objectName, baseClass, environment);
   }

   /* ***********************************************************************
    * protected toolkit Context methods
    ************************************************************************/

   /**
    * Lists all NDS Attribute Definitions for current session
    */
   protected NamingEnumeration schema_list (
         Continuation cont)
      throws NamingException
   {
      cont.setSuccess ();
      return new AttributeDefinitionsNameClassEnumerator (this);
   }

   /**
    * Lists all NDS Attribute Definitions for current session
    */
   protected NamingEnumeration schema_listBindings (
         Continuation cont)
      throws NamingException
   {
      cont.setSuccess ();
      return new AttributeDefinitionsBindingEnumerator (this);
   }

   /**
    * Deletes an attribute definition from the Directory Schema.
    * An attribute definition can be deleted only if it is not in use
    * in any object class definition, and only if the attribute definition
    * is not flagged as used by the name server.
    * Clients cannot subtract from the standard set of attribute definitions
    * defined by the Directory Base Schema (these are flagged nonremovable).
    * Clients can, however, add and remove non-standard definitions
    * (if not in use).
    */
   protected void schema_destroySubcontext (
         String name,
         Continuation cont)
      throws NamingException
   {
      // Make sure binding exists
      if (false == exists (name))
      {
         cont.setError (this, name);
         NameNotFoundException e = new NameNotFoundException ();
         throw cont.fillInException (e);
      }

      try
      {
         NetService service = environment.getService ();

         service.removeAttrDef (name);
      }
      catch (NSIException e)
      {
			NamingException ne = exceptionFactory.getNamingException (e);

         cont.setError (this, name);
         throw (cont.fillInException (ne));
      }
      catch (SessionException e)
      {
         NamingException ne = new NamingException ();

         cont.setError (this, name);
         ne.setRootCause (e);
         throw (cont.fillInException (ne));
      }
      catch (RemoteException e)
      {
         NamingException ne = new NamingException ();

         cont.setError (this, name);
         ne.setRootCause (e);
         throw (cont.fillInException (ne));
      }

      cont.setSuccess ();
   }

   /* ***********************************************************************
    * protected toolkit DirContext methods
    ************************************************************************/

   /**
    * Creates a new NDS attribute definition and binds to the specified name.
    * The name of the new attribute must be unique within the
    * Directory Schema attribute definitions.
    * New attribute names should be cleared through Developer Support
    * to guarantee uniqueness.
    */
   protected DirContext schema_createSubcontext (
         String name,
         Attributes attrs,
         Continuation cont)
      throws NamingException
   {

      if (isEmpty (name))
      {
         cont.setError (this, name);
         throw cont.fillInException (new InvalidNameException ());
      }

      String target = nameParser.parse (name).get (0);

      // See if attribute currently exists
      if (exists (target))
      {
         cont.setError (this, name);
         throw cont.fillInException (new NameAlreadyBoundException ());
      }

      if (attrs == null)
      {
         attrs = new BasicAttributes ();
      }

      // Create new attribute def.  This is done by extracting the necessary
      // information from the attribute set and calling the appropriate
      // native method/
      try
      {
         // Values for NetAttributeInfo constructor
         long flags = 0;
         long syntaxID = 0;
         long lower = 0;
         long upper = 0;
         NetAsn1ID asn1ID = new NetAsn1ID ();

         // Load attributes in order to extract attr values
         Attribute aFlags = attrs.get (
            NetAttributeDefinitionDirContext.ATTR_FLAGS);
         Attribute aSyntaxID = attrs.get (
            NetAttributeDefinitionDirContext.ATTR_SYNTAX_ID);
         Attribute aLower = attrs.get (
            NetAttributeDefinitionDirContext.ATTR_LOWER_LIMIT);
         Attribute aUpper = attrs.get (
            NetAttributeDefinitionDirContext.ATTR_UPPER_LIMIT);
         Attribute aAsn1ID = attrs.get (
            NetAttributeDefinitionDirContext.ATTR_ASN1NAME);

         // Get flags for NetAttributeInfo constructor
         if (null != aFlags)
         {
            flags = ((NdsInteger)
                     aFlags.getAll ().nextElement ()).getInteger ();
         }

         // Get syntaxID for NetAttributeInfo constructor
         if (null != aSyntaxID)
         {
            syntaxID = ((NdsInteger)
                     aSyntaxID.getAll ().nextElement ()).getInteger ();
         }

         // Get lower for NetAttributeInfo constructor
         if (null != aLower)
         {
            lower = ((NdsInteger)
                     aLower.getAll ().nextElement ()).getInteger ();
         }

         // Get upper for NetAttributeInfo constructor
         if (null != aUpper)
         {
            upper = ((NdsInteger)
                     aUpper.getAll ().nextElement ()).getInteger ();
         }

         // Get asn1ID for NetAttributeInfo constructor
         if (null != aAsn1ID)
         {
            asn1ID.setData (((NdsOctetString) aAsn1ID.
                           getAll ().nextElement ()).
                           getOctetString ());
         }

         // Construct NetAttributeInfo with values
         NetAttributeInfo attrInfo = new NetAttributeInfo (
                              (int) flags,
                              (int) syntaxID,
                              (int) lower,
                              (int) upper,
                              asn1ID);

         NetService service = environment.getService ();

         // Create the new attribute def
         service.defineAttr (target, attrInfo);

         return (DirContext)a_lookup (name, cont);
      }
      catch (NSIException e)
      {
			NamingException ne = exceptionFactory.getNamingException (e);

         cont.setError (this, name);
         throw (cont.fillInException (ne));
      }
      catch (SessionException e)
      {
         NamingException ne = new NamingException ();

         cont.setError (this, name);
         ne.setRootCause (e);
         throw (cont.fillInException (ne));
      }
      catch (RemoteException e)
      {
         NamingException ne = new NamingException ();

         cont.setError (this, name);
         ne.setRootCause (e);
         throw (cont.fillInException (ne));
      }

   } /* schema_createSubcontext () */

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

   /**
    * Returns true if the named attribute exists.
    * This is called by various bind/create/delete type methods.
    */
   protected boolean exists (
         String name)
   {
      try
      {
         NetIterationHandle iterationHandle = new NetIterationHandle (
                                             getService (),
                                             NetJNI.DSV_READ_ATTR_DEF);

         NetBuffer attrNames = new NetBuffer (getService (),
                                    NetJNI.DSV_READ_ATTR_DEF,
                                    environment.getBatchSize ());

         NetReadAttrDefBuffer attrDefs = new NetReadAttrDefBuffer (
                        getService (),
                        NetJNI.DS_ATTR_DEF_NAMES,
                        environment.getBatchSize ());

         attrNames.putAttributeName (name);

         NetService service = environment.getService ();

         service.readAttrDef (
                        NetJNI.DS_ATTR_DEF_NAMES,
                        false,
                        attrNames.getHandle (),
                        iterationHandle,
                        attrDefs);

         return true;
      }
      catch (Exception e)
      {
      }
      return false;
   }

} /* NetAttributeDefinitionsDirContext */


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

/** @internal
 * NamingEnumeration subclass setup specifically for
 * NetAttributeDefinitionsDirContext.  This will enumerate all
 * Attribute Definitions.
 */
class AttributeDefinitionsNameClassEnumerator implements NamingEnumeration
{
   private NetAttributeDefinitionsDirContext attrDefsContext;
   private NetEnvironment environment;

   private NetService service;
   private NetIterationHandle iterationHandle;
   private NetReadAttrDefBuffer attrDefs;

   private Enumeration entries;

   private static NdsNamingExceptionFactory exceptionFactory =
       new NdsNamingExceptionFactory ();

   /**
    * Default Constructor.
    *
    * @param attrDefsContext     The NetAttributeDefinitionsDirContext
    *                            constructing this class.
    */
   public AttributeDefinitionsNameClassEnumerator (
         NetAttributeDefinitionsDirContext attrDefsContext)
      throws NamingException
   {
      try
      {
         this.attrDefsContext = attrDefsContext;
         environment = attrDefsContext.environment;
         service = attrDefsContext.getService ();

         iterationHandle = new NetIterationHandle (
                                 service,
                                 NetJNI.DSV_READ_ATTR_DEF);

         attrDefs = new NetReadAttrDefBuffer (
                        service,
                        NetJNI.DS_ATTR_DEF_NAMES,
                        attrDefsContext.environment.getBatchSize ());

         getAttrDefs ();
      }
      catch (NSIException e)
      {
			NamingException ne = exceptionFactory.getNamingException (e);
         throw ne;
      }

   } /* AttributeDefinitionsNameClassEnumerator () */

   /**
    * Returns false only when attrDefs buffer is empty and there are
    * no more iterations of NWDSReadAttrDef to perform.
    */
   public boolean hasMoreElements ()
   {
      if (!entries.hasMoreElements () && !iterationHandle.moreIterations ())
      {
         return (false);
      }
      return (true);
   }

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

   /**
    *
    */
   private void getAttrDefs ()
      throws NSIException
   {
      try
      {
         // Execute the NWDSReadAttrDef native method
         service.readAttrDef (
                        NetJNI.DS_ATTR_DEF_NAMES,
                        true,
                        0,
                        iterationHandle,
                        attrDefs);

         entries = attrDefs.getEntries ();
      }
      catch (SessionException e)
      {
         NSIException ne = new NSIException ();

         ne.setRootCause (e);
         throw (ne);
      }
      catch (RemoteException e)
      {
         NSIException ne = new NSIException ();

         ne.setRootCause (e);
         throw (ne);
      }

   } /* getAttrDefs () */

   /**
    * Returns the next element in the attrDefs buffer.  If the buffer is
    * empty, it attempts to refill it.
    */
   public Object nextElement ()
   {
      try
      {
         return (next ());
      }
      catch (NamingException e)
      {
         throw (new NoSuchElementException ());
      }
   }

   /**
    *
    */
   public Object next ()
      throws NamingException
   {
      if (!this.hasMoreElements ())
      {
         throw new NoSuchElementException ();
      }

      try
      {
         if (!entries.hasMoreElements ())
         {
            // No more elements in this buffer, get next buffer
            getAttrDefs ();
         }

         // Get next element from this buffer
         NetAttrInfo attrInfo = (NetAttrInfo) entries.nextElement ();

         return (new NameClassPair (
                        attrInfo.getName (),
                        Schema.SCHEMA_ATTRIBUTE));
      }
      catch (NSIException e)
      {
			NamingException ne = exceptionFactory.getNamingException (e);
         throw (ne);
      }

   } /* next () */

   /**
    *
    */
   public void close ()
      throws NamingException
   {
      try
      {
         iterationHandle.closeIteration ();
      }
      catch (NSIException e)
      {
         NamingException ne = exceptionFactory.getNamingException (e);
         throw (ne);
      }
   }

} /* AttributeDefinitionsNameClassEnumerator */


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

/** @internal
 * NamingEnumeration subclass setup specifically for
 * NetAttributeDefinitionsDirContext.  This will enumerate all
 * Attribute Definitions.
 */
class AttributeDefinitionsBindingEnumerator implements NamingEnumeration
{
   private static ContextFactory factory = new SchemaContextFactory ();
   private static NdsNamingExceptionFactory exceptionFactory =
       new NdsNamingExceptionFactory ();

   private NetAttributeDefinitionsDirContext attrDefsContext;
   private NetEnvironment environment;

   private NetService service;
   private NetIterationHandle iterationHandle;
   private NetReadAttrDefBuffer attrDefs;

   private Enumeration entries;


   /**
    * @param attrDefsContext     The NetAttributeDefinitionsDirContext
    *                            constructing this class.
    */
   public AttributeDefinitionsBindingEnumerator (
         NetAttributeDefinitionsDirContext attrDefsContext)
      throws NamingException
   {
      try
      {
         this.attrDefsContext = attrDefsContext;
         environment = attrDefsContext.environment;
         service = attrDefsContext.getService ();

         iterationHandle = new NetIterationHandle (
                                 service,
                                 NetJNI.DSV_READ_ATTR_DEF);

         attrDefs = new NetReadAttrDefBuffer (
                        service,
                        NetJNI.DS_ATTR_DEFS,
                        attrDefsContext.environment.getBatchSize ());

         getAttrDefs ();
      }
      catch (NSIException e)
      {
			NamingException ne = exceptionFactory.getNamingException (e);
         throw ne;
      }
   }

   /**
    *
    */
   public boolean hasMoreElements ()
   {
      if (!entries.hasMoreElements () && !iterationHandle.moreIterations ())
      {
         return (false);
      }
      return (true);
   }

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

   /**
    *
    */
   private void getAttrDefs ()
      throws NSIException
   {
      // Execute the NWDSReadAttrDef native method
      try
      {
         service.readAttrDef (
                        NetJNI.DS_ATTR_DEFS,
                        true,
                        0,
                        iterationHandle,
                        attrDefs);

         entries = attrDefs.getEntries ();
      }
      catch (SessionException e)
      {
         NSIException ne = new NSIException ();

         ne.setRootCause (e);
         throw (ne);
      }
      catch (RemoteException e)
      {
         NSIException ne = new NSIException ();

         ne.setRootCause (e);
         throw (ne);
      }

   } /* getAttrDefs () */

   /**
    * Returns the next element in the attrDefs buffer.  If the buffer is
    * empty, it attempts to refill it.
    */
   public Object nextElement ()
   {
      try
      {
         return (next ());
      }
      catch (NamingException e)
      {
         throw (new NoSuchElementException ());
      }
   }

   /**
    *
    */
   public Object next ()
      throws NamingException
   {
      if (!this.hasMoreElements ())
      {
         throw new NoSuchElementException ();
      }


      try
      {
         if (!entries.hasMoreElements ())
         {
            // No more elements in this buffer, get next buffer
            getAttrDefs ();
         }

         StringBuffer distinguishedName;

         // Get next element from this buffer
         NetAttrInfo attrInfo = (NetAttrInfo) entries.nextElement ();

         distinguishedName = new StringBuffer (NetService.MAX_DN_CHARS);
         distinguishedName.append ("\"");
         distinguishedName.append (attrInfo.getName ());
         distinguishedName.append ("\".");
         distinguishedName.append (attrDefsContext.getDistinguishedName ());

         return (new Binding (
                        attrInfo.getName (),
                        factory.getContextInstance (
                                    new String (distinguishedName),
                                    attrInfo,
                                    environment)));
      }
      catch (NSIException e)
      {
			NamingException ne = exceptionFactory.getNamingException (e);
         throw (ne);
      }

   } /* next () */

   /**
    *
    */
   public void close ()
      throws NamingException
   {
      try
      {
         iterationHandle.closeIteration ();
      }
      catch (NSIException e)
      {
         NamingException ne = exceptionFactory.getNamingException (e);
         throw (ne);
      }
   }

} /* AttributeDefinitionsBindingEnumerator */


