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

  $Archive: /njcl_v2rmi/src/com/novell/service/nds/naming/net/NetReplicaDirContext.java $
  $Revision: 12 $
  $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.CompositeName;
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.NSIException;

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

import com.novell.utility.naming.EmptyNamingEnumerator;


/** @internal
 * Represents the second level of (partition Context) objects in the
 * Partition name sapce.
 */
public class NetReplicaDirContext
   extends AtomicDirContext
   implements NdsReplica
{

   private static NdsPartitionNameParser parser = new NdsPartitionNameParser();;
   protected NetEnvironment net;
   private String thisReplicaName;
   private String thisPartnName;
   private PartitionFunctions pf = null;

   /**
   * @param name    Name of the replica
   * @param partnName   Name of the partition (parent's name)
   * @param env NetEnvironament
   * @exception NamingException if the passed name does not represent
   *                             a replica of the given partition
   */
   public NetReplicaDirContext(
            String name,
            String partnName,
            NetEnvironment env)
        throws NamingException
   {
      // Creat an NDS session through the NetEnvironment object
      net = (NetEnvironment)env.clone();
      // Check whether the passed name is a valid one
      pf = new PartitionFunctions(net);
      if(!pf.IsAReplica(name, partnName))
         throw new NameNotFoundException();
      // Save its name
      thisReplicaName = name;
      thisPartnName = partnName;
   }

   /**
    * @param name    Name of the replica
    * @param partnName   Name of the partition (parent's name)
    * @param env NetEnvironament
    * @exception NamingException if the passed name does not represent
    *                             a replica of the given partition
    */
   public NetReplicaDirContext(
            Name name,
            NetEnvironment env)
        throws NamingException
   {
      // Creat an NDS session through the NetEnvironment object
      net = (NetEnvironment)env.clone();

      pf = new PartitionFunctions (net);

      // Save its name
      thisReplicaName = name.get (1);
      thisPartnName = name.get (0);
   }


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

   /** @internal
    *
    */
   public String getNameInNamespace ()
      throws NamingException
   {
      return (thisPartnName + "/" + thisReplicaName);
   }

   /**
   * Place up to 2 components in the head, rest of name in the tail
   * @param name                 name to parse
   * @param cont                 continuation object
   */
   protected HeadTail p_parseComponent(
         Name name,
         Continuation cont)
      throws NamingException
   {
       // If the name has more than 1 component (replica name) at this level,
       //throw exception
      if(name.size() > 1)
          throw cont.fillInException(new InvalidNameException());
      else
         return new HeadTail(name, null);
   }

   /**
   * place first component in the head, rest in the tail
   * @param name                 name to parse
   * @param cont                 continuation object
   */
   protected StringHeadTail c_parseComponent(
         String name,
         Continuation cont)
      throws NamingException
   {
      try
      {
         CompoundName n = (CompoundName)parser.parse(name);
         if(n.isEmpty() || n.size() == 1)
         {
            return new StringHeadTail(name, null);
         }
         else
         {
            throw cont.fillInException(new InvalidNameException());
         }
      }
      catch (NamingException e)
      {
         throw cont.fillInException(e);
      }
   }


   protected Object a_lookup(
         String name,
         Continuation cont)
      throws NamingException
   {
      if(isEmpty(name))
      {
         cont.setSuccess();
         return this;
      }
      else
      {
         return (Object)notSupported(name, cont);
      }

   }

   protected Object a_lookupLink(
         String name,
         Continuation cont)
      throws NamingException
   {
      return a_lookup(name, cont);
   }

   protected NamingEnumeration a_list(
         Continuation cont)
      throws NamingException
   {
      cont.setSuccess ();
      return (new EmptyNamingEnumerator ());
   }

   protected NamingEnumeration a_listBindings(
         Continuation cont)
      throws NamingException
   {
      cont.setSuccess ();
      return (new EmptyNamingEnumerator ());
   }

   protected void a_bind(
         String name,
         Object obj,
         Continuation cont)
      throws NamingException
   {
      notSupported(name, cont);
   }

   protected void a_rebind(
         String name,
         Object obj,
         Continuation cont)
      throws NamingException
   {
      notSupported(name, cont);
   }

   protected void a_unbind(
         String name,
         Continuation cont)
      throws NamingException
   {
      notSupported(name, cont);
   }

   protected void a_rename(
         String oldname,
         Name newname,
         Continuation cont)
      throws NamingException
   {
      notSupported(oldname, cont);
   }

   protected void a_destroySubcontext(
         String name,
         Continuation cont)
      throws NamingException
   {
      notSupported(name, cont);
   }

   protected Context a_createSubcontext(
         String name,
         Continuation cont)
      throws NamingException
   {
      return (Context)notSupported(name, cont);
   }

   protected NameParser a_getNameParser(
         Continuation cont)
      throws NamingException
   {
      return parser;
   }

   /**
    *
    *
   public Properties addToEnvironment (
         Properties additions)
      throws NamingException
   {
      return (net.addToEnvironment (additions));

   } * addToEnvironment () */

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

   } /* addToEnvironment () */

   /**
    *
    *
   public Properties removeFromEnvironment (
         Properties deletions)
      throws NamingException
   {
      return (net.removeFromEnvironment (deletions));

   } * removeFromEnvironment () */

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

   } /* removeFromEnvironment () */

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

   } /* getEnvironment () */


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


   /**
   *  Common code for setting up and throwing OperationNotSupported Exception.
   */
   private Object notSupported(
         String n,
         Continuation c)
      throws NamingException
   {
      c.setError(this, n);
      throw c.fillInException(new OperationNotSupportedException());
   }

   /**
   * ----------------AtomicDirContext toolkits's 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 ());
   }


   /**
   *
   */
   protected Attributes a_getAttributes (
         String name,
         String[] attrIDs,
         Continuation cont)
      throws NamingException
   {
      NetReplicaAttributes ret = null;

      if (! isEmpty (name))
      {
         resolveNext (name, cont);
         return null;
      }

      try
      {
          ret = new NetReplicaAttributes(
                            thisReplicaName,
                            thisPartnName,
                            net,
                            attrIDs);
          cont.setSuccess();
      }
      catch(NamingException e)
      {
         cont.setError (this, name);
         throw cont.fillInException(e);
      }
      return ret;
   }

   /**
    *
    *
    */
   protected void a_modifyAttributes (
         String name,
         int mod_op,
         Attributes attrs,
         Continuation cont)
      throws NamingException
   {
      if (! isEmpty (name))
      {
         resolveNext (name, cont);
      }

       // Allow modification of only Replica Type attribute
       // Do not allow any action except replace
       if(mod_op != DirContext.REPLACE_ATTRIBUTE)
       {
          cont.setError (this, name);
          throw cont.fillInException(new AttributeModificationException());
       }
       // Extract the attribute type from the attrs
       try
       {
          int type;
          // First extract the replica type attribute from attr
          Attribute replicaType = attrs.get(
                                    NdsPartitionStrings.REPLICA_ATTRID_TYPE);
          if(replicaType == null)
          {
             // throw exception
             cont.setError(this, name);
             throw cont.fillInException(new AttributeModificationException());
          }
          Enumeration enum = replicaType.getAll();
          // Replica type is a single valued attribute
          // So, pick the first one
          if(enum.hasMoreElements())
          {
             type = ((NdsInteger)enum.nextElement()).intValue();
          }
          else
          {
             // throw exception
             cont.setError(this, name);
             throw cont.fillInException(new AttributeModificationException());
          }
          pf.changeReplicaType(thisReplicaName, thisPartnName, type);
          cont.setSuccess();
       }
       catch(NamingException e)
       {
          cont.setError(this, name);
          throw cont.fillInException(e);
       }
   }

   /**
    *
    *
    */
   protected void a_modifyAttributes (
         String name,
         ModificationItem[] mods,
         Continuation cont)
      throws NamingException
   {
      if (! isEmpty (name))
      {
         resolveNext (name, cont);
      }

      // Extract the replica type attribute from the modification
      // Item array
      for (int i = 0; i < mods.length; i++)
      {
         ModificationItem mi = mods[i];
         int op = mi.getModificationOp();
         Attribute attr = mi.getAttribute();
         if((op == DirContext.REPLACE_ATTRIBUTE) &&
                    (attr.getID() ==
                                NdsPartitionStrings.REPLICA_ATTRID_TYPE))
         {
            Attributes as = new BasicAttributes (true);
            as.put(attr);
            a_modifyAttributes(name, op, as, cont);
            return;
         }
      }
      // Otherwise throw exception
      cont.setError(this, name);
      throw cont.fillInException(new AttributeModificationException());
   }

   /**
   *
   *
   */
   protected void a_bind (
         String name,
         Object obj,
         Attributes attrs,
         Continuation cont)
      throws NamingException
   {
      notSupported(name, cont);
   }

   /**
   *
   *
   */
   protected void a_rebind (
         String name,
         Object obj,
         Attributes attrs,
         Continuation cont)
      throws NamingException
   {
      notSupported(name, cont);
   }

   /**
   *
   *
   */
   protected DirContext a_createSubcontext (
         String name,
         Attributes attrs,
         Continuation cont)
      throws NamingException
   {
      return (DirContext)notSupported(name, cont);
   }


   /**
   *  Implementation of NdsReplicaOperations interface
   */


   /**
   *
   *
   */

   public void setReplicaType(
            int type)
        throws NdsPartitionOperationException
   {
       pf.changeReplicaType(thisReplicaName, thisPartnName, type);
   }


   /**
   *
   *
   */

   public void syncReplica(
            String destServer,
            int flags,
            int delay)
        throws NdsPartitionOperationException
   {
      pf.syncReplica(thisReplicaName, thisPartnName, destServer, flags, delay);
   }


   /**
   *
   *
   */

   public void syncReplica(
            int delay)
        throws NdsPartitionOperationException
   {
      pf.syncReplica(thisReplicaName, thisPartnName, delay);
   }

   /**
    * This replica receives updates from the master replica.
    *
    * @exception NSIException
    */
   public void receiveUpdates ()
      throws NSIException
   {
      try
      {
         NetService service = net.getService ();

         service.partitionReceiveAllUpdates (thisPartnName, thisReplicaName);
      }
      catch (Exception e)
      {
         NSIException ne = new NSIException ();

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

   } /* receiveAllUpdates () */

   /**
    * This replica sends updates to all other replicas.
    *
    * @exception NSIException
    */
   public void sendUpdates ()
      throws NSIException
   {
      try
      {
         NetService service = net.getService ();

         service.partitionSendAllUpdates (thisPartnName, thisReplicaName);
      }
      catch (Exception e)
      {
         NSIException ne = new NSIException ();

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

   } /* sendAllUpdates () */

//----------------------------------------------------------------------------
   /**
   *
   */
   protected NamingEnumeration a_search (
         Attributes matchingAttrs,
         String[] returnAttrs,
         Continuation cont)
      throws NamingException
   {
      return (NamingEnumeration)notSupported("", cont);
   }

   /**
   *
   */
   protected NamingEnumeration a_search (
         String name,
         String filterExpr,
         Object [] filterArgs,
         SearchControls cons,
         Continuation cont)
      throws NamingException
   {
      return (NamingEnumeration)notSupported(name, cont);
   }

   /**
    *
    */
   protected NamingEnumeration a_search (
         String name,
         String filter,
         SearchControls cons,
         Continuation cont)
      throws NamingException
   {
      return (NamingEnumeration)notSupported(name, cont);
   }


   /*
   *----------------------Utility Methods -----------------------------
   */

    /**
    * 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, "");
      }
   }

   private String serverName;

   /**
    *
    */
   private String getServerName ()
      throws NSIException
   {
      try
      {
         if (serverName == null)
         {
            Name name;
            NdsNameParser parser = new NdsNameParser ();

            name = parser.parse (thisReplicaName);
            serverName = name.get (name.size () - 1);
         }
         return (serverName);
      }
      catch (NamingException e)
      {
         NSIException ne = new NSIException ();

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

} /* NetReplicaDirContext */


