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

  $Archive: /njcl_v2/src/com/novell/service/nds/naming/net/ListNdsIterator.java $
  $Revision: 9 $
  $Modtime: 8/21/01 4:40p $

  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.io.*;

import java.util.*;

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

import com.sun.jndi.toolkit.*;

import com.novell.service.jncp.*;
import com.novell.service.jncpv2.clx.ClxJNI;

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

import com.novell.service.nds.NdsIterator;
import com.novell.service.nds.NdsIteratorControls;
import com.novell.service.nds.NdsIteratorResult;

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

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

import com.novell.service.toolkit.jcl.NWInteger;

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


/**
 *
 */
public class ListNdsIterator implements NdsIterator, Cloneable
{
   private static ContextFactory factory = new NetContextFactory ();
   private static NdsNamingExceptionFactory exceptionFactory =
       new NdsNamingExceptionFactory ();
   private static NameParser nameParser = new NdsNameParser ();

   protected NetIterator iterator;

   private NetEnvironment environment;
   private NetService service;

   private boolean retObj = false;
   private boolean empty;

   /**
    *
    */
   public ListNdsIterator (
         String objectName,
         NetEnvironment environment,
         String className,
         String subordinateName,
         NdsIteratorControls cons)
      throws NSIException
   {
      this.environment = (NetEnvironment) environment.clone ();
      this.retObj = cons.getReturningObjFlag ();

      try
      {
         this.service = environment.getService ();

         iterator = new NetIterator (
                                       service,
                                       objectName,
                                       className,
                                       subordinateName,
                                       cons.getScalability (),
                                       cons.getTimeLimit ());
      }
      catch (NamingException e)
      {
         NSIException ne = new NSIException ();

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

      empty = iterator.atEOF ();

   } /* ListNdsIterator () */


   /**
    *
    */
   public NdsIteratorInfo getInfo ()
      throws NSIException
   {
      return (iterator.getInfo ());
   }


   /**
    *
    */
   public int getPosition (
         int timeout)
      throws NSIException
   {
      return (iterator.getPosition (timeout));
   }

   /**
    *
    */
   public void setPosition (int position, int timeout)
      throws NSIException
   {
      iterator.setPosition (position, timeout);
   }

   /**
    *
    */
   public void setPosition (
         NdsIterator position,
         int timeout)
      throws NSIException
   {
      iterator.setPosition (((ListNdsIterator) position).iterator, timeout);
   }

   /**
    *
    */
   public void setPosition (
         String attribute,
         String value,
         int timeout)
      throws NSIException
   {
      if (attribute.equalsIgnoreCase ("Name"))
      {
         iterator.setPosition ("_RDN", value, timeout);
      }
      else
      {
         iterator.setPosition (attribute, value, timeout);
      }

   } /* setPosition () */

   /**
    *
    */
   public int skip (int count, int timeout)
      throws NSIException
   {
      return (iterator.skip (count, timeout));
   }

   public boolean hasNext()
      throws NSIException
   {
      return (iterator.atEOF () ? false : true);
   }

   public NamingEnumeration next (int entries, int timeout)
      throws NSIException
   {
      return (new NextEnumerator (entries, timeout));
   }

   public boolean hasPrevious()
      throws NSIException
   {
      return ((!iterator.atFirst () && !empty) ? true : false);
   }

   public NamingEnumeration previous (int entries, int timeout)
      throws NSIException
   {
      return (new PreviousEnumerator (entries, timeout));
   }

   public Object current ()
      throws NSIException
   {
      try
      {
         return ((new CurrentEnumerator ()).next ());
      }
      catch (NamingException e)
      {
         NSIException ne = new NSIException ();

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

   } /* current () */

   /**
    *
    */
   public int count (int timeout, int maxCount, boolean updatePosition)
      throws NSIException
   {
      return (iterator.count (timeout, maxCount, updatePosition));
   }


   /**
    * Closes the Iterator and frees all associated memory.
    */
   public void close ()
      throws NSIException
   {
      iterator.destroy ();
   }



   // ******************** Object Class ********************

   /**
    * Creates a new object of the same class as this object. It
    * then initializes each of the new object's fields by assigning
    * them the same value as the corresponding fields in this object.
    * No constructor is called.
    *
    * @return A clone of this object instance containing the cloned
    *         syntax.
    *
    * @exception CloneNotSupportedException The object's class does
    *            not support the Cloneable interface.
    */
   public Object clone ()
   {
      try
      {
         ListNdsIterator iterator = (ListNdsIterator) super.clone ();

         iterator.iterator = (NetIterator) this.iterator.clone ();
         iterator.environment = (NetEnvironment) this.environment.clone ();

         iterator.service = iterator.environment.getService ();

         iterator.retObj = this.retObj;

         return (iterator);
      }
      catch (CloneNotSupportedException e)
      {
         // this shouldn't happen, since we are Cloneable
         throw (new InternalError ());
      }
      catch (NamingException e)
      {
         NSIException ne = new NSIException ();

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

   } /* clone () */


   /**
    *
    */
   class NextEnumerator implements NamingEnumeration
   {
      private int entries;
      private int timeout;
      private NetIterationHandle iteration;
      private NetBuffer objectInfo;

      private int objectCount;
      private SearchObject nextSearchObject;

      /**
       *
       */
      public NextEnumerator (int entries, int timeout)
      {
         this.entries = entries;
         this.timeout = timeout;

         iteration = new NetIterationHandle (service, NetJNI.DSV_ITERATOR);
         objectInfo = new NetBuffer (service, environment.getBatchSize ());

         nextSearchObject = getFirstSearchObject ();
      }

      /**
       *
       */
      public boolean hasMoreElements ()
      {
         return (hasMore ());
      }

      /**
       *
       */
      public boolean hasMore ()
      {
         if (null == nextSearchObject)
         {
            return (false);
         }
         return (true);
      }

      /**
       *
       */
      private int updateObjectInfo ()
         throws NSIException
      {
         iterator.getNext (entries, timeout, iteration, objectInfo);
         return (objectInfo.getObjectCount ());
      }

      /**
       *
       */
      private SearchObject getFirstSearchObject ()
         throws NSIException
      {
         try
         {
            if (0 == (objectCount = updateObjectInfo ()))
            {
               return (null);
            }
            objectCount--;
            return (new SearchObject (objectInfo, environment));
         }
         catch (NamingException e)
         {
            throw (new NSIException ());
         }

      } /* getFirstSearchObject () */

      /**
       *
       */
      private SearchObject getNextSearchObject ()
         throws NSIException
      {
         try
         {
            while (0 == objectCount)
            {
               if (!iteration.moreIterations ())
               {
                  return (null);
               }
               objectCount = updateObjectInfo ();
            }
            objectCount--;
            return (new SearchObject (objectInfo, environment));
         }
         catch (NamingException e)
         {
            throw (new NSIException ());
         }

      } /* getNextSearchObject () */

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

      /**
       *
       */
      public Object next ()
         throws NamingException
      {
         if (!hasMore ())
         {
            throw (new NoSuchElementException ());
         }
         try
         {
            Context context = null;
            SearchObject currentSearchObject = nextSearchObject;

            nextSearchObject = getNextSearchObject ();

            // handle search objects in multiple iterations
            while (currentSearchObject.equalsApproximate (nextSearchObject))
            {
               Attributes attrs = nextSearchObject.getAttributes ();

               currentSearchObject.mergeAttributes (attrs);
               nextSearchObject = getNextSearchObject ();
            }

            if (retObj)
            {
               // create DirContext
               context = factory.getContextInstance (
                                        currentSearchObject.getName (),
                                        currentSearchObject.getNdsObjectInfo (),
                                        environment);
            }

            Name name = nameParser.parse (currentSearchObject.getName ());

            return (new NdsIteratorResult (
                           name.get (name.size () - 1),
                           context,
                           currentSearchObject.getAttributes (),
                           currentSearchObject.getNdsObjectInfo (),
                           true));
         }
         catch (NSIException e)
         {
            NamingException ne = exceptionFactory.getNamingException (e);
            throw (ne);
         }

      } /* next () */

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

   } /* NextEnumerator */

   /**
    *
    */
   class PreviousEnumerator implements NamingEnumeration
   {
      private int entries;
      private int timeout;
      private NetIterationHandle iteration;
      private NetBuffer objectInfo;

      private int objectCount;
      private SearchObject nextSearchObject;

      /**
       *
       */
      public PreviousEnumerator (int entries, int timeout)
      {
         this.entries = entries;
         this.timeout = timeout;

         iteration = new NetIterationHandle (service, NetJNI.DSV_ITERATOR);
         objectInfo = new NetBuffer (service, environment.getBatchSize ());

         nextSearchObject = getFirstSearchObject ();
      }

      /**
       *
       */
      public boolean hasMoreElements ()
      {
         return (hasMore ());
      }

      /**
       *
       */
      public boolean hasMore ()
      {
         if (null == nextSearchObject)
         {
            return (false);
         }
         return (true);
      }

      /**
       *
       */
      private int updateObjectInfo ()
         throws NSIException
      {
         iterator.getPrev (entries, timeout, iteration, objectInfo);
         return (objectInfo.getObjectCount ());
      }

      /**
       *
       */
      private SearchObject getFirstSearchObject ()
         throws NSIException
      {
         try
         {
            if (0 == (objectCount = updateObjectInfo ()))
            {
               return (null);
            }
            objectCount--;
            return (new SearchObject (objectInfo, environment));
         }
         catch (NamingException e)
         {
            throw (new NSIException ());
         }

      } /* getFirstSearchObject () */

      /**
       *
       */
      private SearchObject getNextSearchObject ()
         throws NSIException
      {
         try
         {
            while (0 == objectCount)
            {
               if (!iteration.moreIterations ())
               {
                  return (null);
               }
               objectCount = updateObjectInfo ();
            }
            objectCount--;
            return (new SearchObject (objectInfo, environment));
         }
         catch (NamingException e)
         {
            throw (new NSIException ());
         }

      } /* getNextSearchObject () */

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

      /**
       *
       */
      public Object next ()
         throws NamingException
      {
         if (!hasMoreElements ())
         {
            throw (new NoSuchElementException ());
         }
         try
         {
            Context context;
            SearchObject currentSearchObject = nextSearchObject;

            nextSearchObject = getNextSearchObject ();

            // handle search objects in multiple iterations
            while (currentSearchObject.equalsApproximate (nextSearchObject))
            {
               Attributes attrs = nextSearchObject.getAttributes ();

               currentSearchObject.mergeAttributes (attrs);
               nextSearchObject = getNextSearchObject ();
            }

            // create DirContext
            context = factory.getContextInstance (
                                     currentSearchObject.getName (),
                                     currentSearchObject.getNdsObjectInfo (),
                                     environment);

            Name name = nameParser.parse (currentSearchObject.getName ());

            return (new NdsIteratorResult (
                           name.get (name.size () - 1),
                           (retObj) ? context : null,
                           currentSearchObject.getAttributes (),
                           currentSearchObject.getNdsObjectInfo (),
                           true));
         }
         catch (NSIException e)
         {
            NamingException ne = exceptionFactory.getNamingException (e);
            throw (ne);
         }

      } /* next () */

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

   } /* PreviousEnumerator */

   /**
    *
    */
   class CurrentEnumerator implements NamingEnumeration
   {
      private int entries;
      private int timeout;
      private NetIterationHandle iteration;
      private NetBuffer objectInfo;

      private int objectCount;
      private SearchObject nextSearchObject;

      /**
       *
       */
      public CurrentEnumerator ()
      {
         this.entries = 1;
         this.timeout = 0;

         iteration = new NetIterationHandle (service, NetJNI.DSV_ITERATOR);
         objectInfo = new NetBuffer (service, environment.getBatchSize ());

         nextSearchObject = getFirstSearchObject ();
      }

      /**
       *
       */
      public boolean hasMoreElements ()
      {
         return (hasMore ());
      }

      /**
       *
       */
      public boolean hasMore ()
      {
         if (null == nextSearchObject)
         {
            return (false);
         }
         return (true);
      }

      /**
       *
       */
      private int updateObjectInfo ()
         throws NSIException
      {
         iterator.getCurrent (iteration, objectInfo);
         return (objectInfo.getObjectCount ());
      }

      /**
       *
       */
      private SearchObject getFirstSearchObject ()
         throws NSIException
      {
         try
         {
            if (0 == (objectCount = updateObjectInfo ()))
            {
               return (null);
            }
            objectCount--;
            return (new SearchObject (objectInfo, environment));
         }
         catch (NamingException e)
         {
            throw (new NSIException ());
         }

      } /* getFirstSearchObject () */

      /**
       *
       */
      private SearchObject getNextSearchObject ()
         throws NSIException
      {
         try
         {
            while (0 == objectCount)
            {
               if (!iteration.moreIterations ())
               {
                  return (null);
               }
               objectCount = updateObjectInfo ();
            }
            objectCount--;
            return (new SearchObject (objectInfo, environment));
         }
         catch (NamingException e)
         {
            throw (new NSIException ());
         }

      } /* getNextSearchObject () */

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

      /**
       *
       */
      public Object next ()
         throws NamingException
      {
         if (!hasMoreElements ())
         {
            throw (new NoSuchElementException ());
         }
         try
         {
            Context context;
            SearchObject currentSearchObject = nextSearchObject;

            nextSearchObject = getNextSearchObject ();

            // handle search objects in multiple iterations
            while (currentSearchObject.equalsApproximate (nextSearchObject))
            {
               Attributes attrs = nextSearchObject.getAttributes ();

               currentSearchObject.mergeAttributes (attrs);
               nextSearchObject = getNextSearchObject ();
            }

            // create DirContext
            context = factory.getContextInstance (
                                     currentSearchObject.getName (),
                                     currentSearchObject.getNdsObjectInfo (),
                                     environment);

            Name name = nameParser.parse (currentSearchObject.getName ());

            return (new NdsIteratorResult (
                           name.get (name.size () - 1),
                           (retObj) ? context : null,
                           currentSearchObject.getAttributes (),
                           currentSearchObject.getNdsObjectInfo (),
                           true));
         }
         catch (NSIException e)
         {
            NamingException ne = exceptionFactory.getNamingException (e);
            throw (ne);
         }

      } /* next () */

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

   } /* CurrentEnumerator */

} /* ListNdsIterator */


