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

  $Archive: /njcl_v2/src/com/novell/service/file/nw/naming/VolumeDirContext.java $
  $Revision: 11 $
  $Modtime: 1/28/00 12:45p $
 
  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.file.nw.naming;

import java.io.IOException;
import java.util.Hashtable;

import javax.naming.Name; 
import javax.naming.NamingException; 
import javax.naming.NamingEnumeration;
import javax.naming.directory.Attribute;
import javax.naming.directory.AttributeModificationException;
import javax.naming.directory.Attributes;
import javax.naming.directory.ModificationItem;

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

import com.novell.utility.naming.directory.StaticAttributeValue;
import com.novell.utility.naming.directory.NAttributes;

import com.novell.service.file.nw.NetwareVolume;
import com.novell.service.file.nw.VolumeInformation;
import com.novell.service.file.nw.VolumeRestrictionEnumerator;
import com.novell.service.file.nw.VolumeRestriction;
import com.novell.service.file.nw.VolumeUtilization;
import com.novell.service.file.nw.TrusteePathEnumerator;
import com.novell.service.file.nw.calls.VolumeInfoImpl;
import com.novell.service.file.nw.calls.VolumeUtilizationImpl;
import com.novell.service.file.nw.calls.VolumeRestrictionEnumeratorImpl;
import com.novell.service.file.nw.calls.TrusteePathEnumeratorImpl;

import com.novell.service.jncp.NSIException;

/** @internal
 * Represents the root directory of a NetWare volume.  This class extends
 * DirectoryDirContext and is a directory for all intents and purposes.
 *
 * <p>The only difference between this class and DirectoryDirContext is
 * that it does not have a parent directory.  Thus, 'getDirectory()'
 * returns null.
 *
 * <p>In DirEntryDirContext, the name space is retrieved from
 * the parent directory.  The VolumeDirContext does not have a parent
 * directory, and so must be the source of the name space.  Thus, the
 * VolumeDirContext is the source of the name space.  Any internal
 * classes that construct instances of this class must pass in a valid name
 * space.
 *
 * <p>Also, the VolumeDirContext represents the top of the chain of
 * contexts used to construct a native dir entry name.  Even though the
 * volume name is not a dir entry, the VolumeDirContext is a dir entry --
 * it is the unnamed root directory in that volume.
 *
 * @see DirEntryDirContext
 */
public class VolumeDirContext 
   extends DirectoryDirContext
   implements NetwareVolume
{
   private static final int VI_SAV = 0;
   private static final int VU_SAV = 1;
   private static final int VR_SAV = 2;
   private static final int TP_SAV = 3;

   private StaticAttributeValue[] attributeValues = null;

   /**
    * Constructs a VolumeDirContext 
    *
    * @param environment         The File system environment object
    * @exception NamingException When an error occurs getting the server
    *                            name from the connection or when any
    *                            other error occurs.
    */
   public VolumeDirContext(FSEnvironment environment)
      throws NamingException
   {
      // call DirectoryDirContext()
      super(null, environment.getVolumeName(), environment);

      attributeValues = new StaticAttributeValue[4];
      try
      {
         setupDirEntryStaticAttributeValues();
         setupDirectoryStaticAttributeValues();
         
         attributeValues[VI_SAV] = new VolumeInfoImpl(
                                          environment);

         attributeValues[VU_SAV] = new VolumeUtilizationImpl(
                                          environment);

         attributeValues[VR_SAV] = new VolumeRestrictionEnumeratorImpl(
                                          environment);

         attributeValues[TP_SAV] = new TrusteePathEnumeratorImpl(
                                          environment);
      }catch(NSIException e)
      {
         NamingException ne = new NamingException();
         ne.setRootCause(e);
         throw ne;
      }
   }

/* *************************************************************************
* volume interface implementation
****************************************************************************/

   /**
    * Returns the VolumeInformation object associated with this file.
    * 
    * @return                    The VolumeInformation object.
    */
   public VolumeInformation getVolumeInformation()
   {
      return (VolumeInformation)
         attributeValues[VI_SAV].getStaticInterface();
   }

   /**
    * Returns the VolumeUtilization object associated with this file.
    * 
    * @return                    The VolumeUtilization object.
    */
   public VolumeUtilization getVolumeUtilization()
   {
      return (VolumeUtilization)
         attributeValues[VU_SAV].getStaticInterface();
   }

   /**
    * Returns the VolumeRestrictionEnumerator object associated with this file.
    * 
    * @return                    The VolumeRestrictionEnumerator object.
    */
   public VolumeRestrictionEnumerator getVolumeRestrictionEnumerator()
   {
      return (VolumeRestrictionEnumerator)
         attributeValues[VR_SAV].getStaticInterface();
   }

   /**
    * Modifies the Backend VolumeRestriction object associated with 
    * this volume.
    *
    * @param      vr             The VolumeRestriction modify value.
    * @param      mod_op         The modification to preform if the
    *                            attribute is part of the set, valid values
    *                            are:
    *                            DirContext.ADD_ATTRIBUTE,
    *                            DirContext.DELETE_ATTRIBUTE, and
    *                            DirContext.REPLACE_ATTRIBUTE.
    */
   public void setVolumeRestriction(
      VolumeRestriction vr,
      int mod_op)
   {
      setStaticInterface(
         attributeValues[VR_SAV], 
         mod_op, 
         attributeValues[VR_SAV].getID(),
         vr);
   }

   /**
    * Returns the TrusteePathEnumerator object associated with this file.
    * 
    * @return                    The TrusteePathEnumerator object.
    */
   public TrusteePathEnumerator getTrusteePathEnumerator()
   {
      return (TrusteePathEnumerator)
         attributeValues[TP_SAV].getStaticInterface();
   }

/* **************************************************************************
   DSContext methods that are overridden from DirEntryDirContext
****************************************************************************/

   /**
    * Get attributes.
    *
    * <p>Retrieves all the attributes associated with named object.
    * </p>
    *
    * @param      name           The string name of the object for which 
    *                            to retrieve the attributes.  If name is the 
    *                            empty string, retrieves the attributes of 
    *                            this context object.
    * @param      attrIds        The list of attribute ID's to be included
    *                            in the returned AttributeSet. 
    * @param      cont           Continuation object to be maintained
    *                            for downstream federation.
    * @return                    The attributes associated with 'name' and 
    *                            requested by the itemized attrIds list.
    * @exception NamingException When an error occurs retrieving this
    *                            context's attributes.
    */
   protected Attributes c_getAttributes(
      Name name, 
      String[] attrIds,
      Continuation cont)
      throws NamingException
   {
      if (!name.isEmpty())
      {
         resolveNext(name, cont);
         return null;
      }

      try
      {
         Attributes as = new NAttributes(true);
         addAttributes(as, attrIds, attributeValues);
         addAttributes(as, attrIds, super.attributeValues);
         addAttributes(as, attrIds, getDirEntryAttributeValues());
         cont.setSuccess();
         return (as);
      }
      catch (NSIException e)
      {
         NamingException ne = new NamingException();

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

         throw ne;
      } 
   }

   /**
    * Modify attributes.
    *
    * <p>Modifies the attributes associated with named object.
    * </p>
    *
    * @param      name           The string name of the object for which 
    *                            to modify the attributes.  If name is the 
    *                            empty string, modifies the attributes of 
    *                            this context object.
    * @param      mod_op         The type of modification to do to with the
    *                            attrs given.  Possible values are:
    *                            DSContext.ADD_ATTRIBUTE,
    *                            DSContext.REPLACE_ATTRIBUTE, and
    *                            DSContext.DELETE_ATTRIBUTE
    *                            in the returned AttributeSet. 
    * @param      attrs          The AttributeSet to be applied, in the 
    *                            manner specified in mod_op.
    * @param      cont           Continuation object to be maintained
    *                            for downstream federation.
    * @exception AttributeModificationException When 'mod_op' is an invalid
    *                            operation for a given attribute ID, or
    *                            when an error occurred when performing
    *                            the operation.
    */
   protected void c_modifyAttributes(
      Name name, 
      int mod_op,
      Attributes attrs,
      Continuation cont) 
      throws NamingException
   {
      if (!name.isEmpty())
      {
         resolveNext(name, cont);
         return;
      }

      NamingEnumeration enum = attrs.getAll();

      if (enum == null)    // if the set is empty, do nothing!
         return;        

      while (enum.hasMoreElements())
      {
         Attribute attr = (Attribute)enum.next();
         if (!modifyAttributes(
                  attr, mod_op, attributeValues, name, cont))
         {
            cont.setError(this, name);
            throw cont.fillInException(
                           new 
                           AttributeModificationException(
                              attr.getID()));
         }
      }
      cont.setSuccess();
   }

   /**
    * Modify attributes.
    *
    * <p>Modifies the attributes associated with named object.
    * </p>
    *
    * @param      name           The string name of the object for which 
    *                            to modify the attributes.  If name is the 
    *                            empty string, modifies the attributes of 
    *                            this context object.
    * @param      mod_op         The type of modification to do to with the
    *                            attrs given.  Possible values are:
    *                            DSContext.ADD_ATTRIBUTE,
    *                            DSContext.REPLACE_ATTRIBUTE, and
    *                            DSContext.DELETE_ATTRIBUTE
    *                            in the returned AttributeSet. 
    * @param      attrs          The AttributeSet to be applied, in the 
    *                            manner specified in mod_op.
    * @param      cont           Continuation object to be maintained
    *                            for downstream federation.
    * @exception AttributeModificationException When 'mod_op' is an invalid
    *                            operation for a given attribute ID, or
    *                            when an error occurred when performing
    *                            the operation.
    */
   protected void c_modifyAttributes(
      Name name, 
      ModificationItem[] mods,
      Continuation cont) 
      throws NamingException
   {
      if (!name.isEmpty())
      {
         resolveNext(name, cont);
         return;
      }

      int max = mods.length;
      for (int i=0; i < max; i++)
      {
         ModificationItem mi = mods[i];
         Attribute attr = mi.getAttribute();
         if (!modifyAttributes(
                  attr, mi.getModificationOp(), 
                  attributeValues, name, cont))
         {
            cont.setError(this, name);
            throw cont.fillInException(
                           new 
                           AttributeModificationException(
                              attr.getID()));
         }
      }
      cont.setSuccess();
   }

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

   protected StaticAttributeValue getSubsAttributeValue(String attrId)
   {
//      StaticAttributeValue value;
      
//      if ((value = getAttributeValue(attrId, attributeValues)) == null)
//         value = getAttributeValue(attrId, super.attributeValues);
//      return value;
      return getAttributeValue(attrId, attributeValues);
   }
}
