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

  $Archive: /njcl_v2/src/com/novell/service/file/nw/calls/EffectiveRightsImpl.java $
  $Revision: 9 $
  $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.file.nw.calls;

import java.util.Enumeration;
import java.util.Hashtable;
import java.util.NoSuchElementException;

import java.rmi.RemoteException;

import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.AttributeModificationException;
import javax.naming.directory.InvalidSearchFilterException;

import com.novell.service.jncp.NSIException;

import com.novell.service.session.SessionException;
import com.novell.service.session.xplat.XplatSession;
import com.novell.service.session.xplat.CallsService;
import com.novell.service.jncpv2.net.NetService;

import com.novell.service.file.nw.EffectiveRights;
import com.novell.service.file.nw.NameSpace;

import com.novell.service.file.nw.naming.FSAttribute;
import com.novell.service.file.nw.naming.SchemaAttrDef;
import com.novell.service.file.nw.naming.SchemaSyntaxDef;
import com.novell.service.file.nw.naming.FSEnvironment;

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

import com.novell.service.rfc1960.SearchStringComponent;

import com.novell.java.lang.IntegerBuffer;

/**@internal
 * This class allows access to the Effective rights of a directory entry.
 *
 * <p>This class provides the implementation to get the actual values from
 * a NetWare server for a given directory entries effective rights.  The 
 * interface for accessing these values is defined in the EffectiveRights class
 * in the com.novell.service.file.nw package.
 *
 * <p>From the file system JNDI provider's perspective, this class fits in
 * as a single-valued attribute value.  When an attribute set is requested
 * from JNDI, all StaticAttributeValues are iterated through, and the
 * values returned by the StaticAttributeValue.nextElement() method
 * are then the JNDI attribute values stored in an instance of
 * javax.naming.directory.Attribute.  The JNDI attribute has the name
 * as defined in this class in the EffectiveRights.ATTRIBUTE_ID.
 * </p>
 *
 * @see com.novell.service.file.nw.naming.StaticAttributeValue
 * @see com.novell.service.file.nw.EffectiveRights
 * @see com.novell.service.file.nw.naming.FSAttribute
 * @see com.novell.service.file.nw.naming.DirEntryDirContext
 */
public class EffectiveRightsImpl
   extends EffectiveRights
   implements StaticAttributeValue
{

/* **************************************************************************
   private state data members
****************************************************************************/

   private FSEnvironment environment;
   private String fullNodeName;
   private String nameSpace;
   private NetService netService;
   private CallsService callsService;
   private boolean sessionIsNDS;

   private boolean hasMoreElements = true;

/* **************************************************************************
   Public Constructor
****************************************************************************/

   /**
    * Constructs an EffectiveRightsImpl object.
    *
    * @param environment         The JNDI DSContext's environment associated
    *                            with this attribute and this static
    *                            attribute value.
    *
    * @exception NSIException    If an error occurs.
    */

   public EffectiveRightsImpl(FSEnvironment environment)
      throws NSIException
   {
      this.environment = environment;
      fullNodeName = environment.getFullNodeName();

      // this check is to make sure that we can get effective rights
      //   information at the root directory of the volume.  In the root
      //   directory case, 'fullNodeName' will only contain the name of
      //   the volume, and we need to put a colon on the end of it.
      if (fullNodeName.indexOf(':') == -1)
         fullNodeName = fullNodeName + ":";

      nameSpace = environment.getNameSpace();
      try
      {
         this.callsService = environment.getCallsService();
         this.netService = environment.getNetService();
         this.sessionIsNDS = environment.sessionIsNDS();
      } catch (NamingException e)
      {
         throw new NSIException("" + e, e);
      }
   }

   /**
    * Constructs an EffectiveRightsImpl from a EffectiveRights object.
    *
    * @param efr                 The EffectiveRights object to 
    *                            clone into a EffectiveRightsImpl object.
    */

   private EffectiveRightsImpl(
      EffectiveRights efr,
      int userID)
   {
      super(efr.getRights(), efr.getUser());      
         this.userId = userId;
   }

/* **************************************************************************
   Enumeration implementation
****************************************************************************/

   /**
    * Tests whether the attribute value has already been returned.
    *
    * <p>Because this EffectiveRights information matches Effective Rights
    * one-to-one, there is only ever one value returned from this
    * classes enumeration.
    * </p>
    *
    * @return                    true if nextElement() has never been called,
    *                            otherwise returns false.
    *
    * @see #nextElement
    * @see #buildAttribute
    */
   public boolean hasMoreElements()
   {
      return hasMoreElements;
   }

   /**
    * Retrieves the attribute value, if it has not yet been retrieved.
    *
    * <p>The StaticAttributeValue interface also declares this method for
    * lazy evaluation of jndi attribute values.  The buildAttribute method
    * will return a FSAttribute which will have a reference to this object.
    * The FSAttribute.getValues method will return an enumerator which will
    * forward the hasMoreElements and nextElement calls back into this
    * object.  One, and only one object will ever be returned from this method.
    * </p>
    *
    * @return                    EffectiveRights object.
    * @exception  NoSuchElementException When the EffectiveRights
    *                            object has already been retrieved.
    * @exception  NSIException   refresh can throw a NSIException.
    *
    * @see #hasMoreElements
    * @see #buildAttribute
    * @see com.novell.service.file.nw.DirectoryEntryInformation
    */
   public Object nextElement()
   {
      if (!hasMoreElements)
         throw new NoSuchElementException();

      hasMoreElements = false;   // only give them one

      refresh();

      return(this);
   }

/* **************************************************************************
   StaticAttributeValue implementation
****************************************************************************/

   /**
    * Builds and returns a JNDI Attribute for this attribute value.
    *
    * @return                    The JNDI Attribute that contains all
    *                            values accessible from this static
    *                            attribute value.
    * @exception NamingException When an error occurs building the new
    *                            JNDI attribute.
    *
    * @see com.novell.service.file.nw.naming.DirEntryDirContext#c_getAttributes
    */
   public Attribute buildAttribute()
      throws NamingException
   {
      EffectiveRightsImpl efr = null;

      try
      {
         efr = new EffectiveRightsImpl(environment);
      } catch (NSIException nsie)
      {
         NamingException ne = new NamingException(nsie.getMessage());
         ne.setRootCause(nsie);
         throw ne;
      }

      return new 
         FSAttribute(
            ATTRIBUTE_ID,
            efr,
            new SchemaAttrDef(SchemaAttrDef.EFR_ATTRDEF, environment),
            new SchemaSyntaxDef(SchemaAttrDef.EFR_ATTRDEF, environment));
   }

   /**
    * Adds all values in a JNDI Attribute to this static attribute value.
    *
    * <p>This static attribute value only supports one value.
    * </p>
    *
    * @param      attr           The attribute containing the values to be
    *                            added.
    * @exception AttributeModificationException Always throws this exception
    *                            because there can never be more than
    *                            one set of effective rights
    */
   public void addAttribute(Attribute attr)
      throws NamingException
   {
      throw new AttributeModificationException();
   }

   /**
    * Deletes all values in a JNDI Attribute from this static attribute
    * value.
    *
    * <p>This static attribute value only supports one value.
    * </p>
    *
    * @param      attr           The attribute containing the values to be
    *                            removed.
    * @exception AttributeModificationException Always throws this exception
    *                            because there can never be less than
    *                            one set of Effective Rights.
    */
   public void deleteAttribute(Attribute attr)
      throws NamingException
   {
      throw new AttributeModificationException();
   }

   /**
    * Modifies the value of this static attribute value as specified by the
    * values in the specified JNDI Attribute.
    *
    * <p>Modifies the current EffectiveRights state to the value of
    * the attribute.  
    *
    * @param      attr           The attribute containing the values to be
    *                            modified.  There can only be one value for
    *                            this static attribute value.
    * @exception AttributeModificationException When the read-only fields
    *                            of the value in specified attribute differ
    *                            with the read-only fields of this static
    *                            attribute value.
    *
    * @see com.novell.service.file.nw.DirectoryEntryInformation
    */
   public void modifyAttribute(Attribute attr)
      throws NamingException
   {
      throw new AttributeModificationException();
   }

   /**
    * Gets this static attribute values Attribute ID.
    *
    * <p>This attribute ID is reflected in the JNDI world as the
    * attribute ID in the attribute set of a directory entry.
    * </p>
    *
    * @return                    The attribute ID.
    *
    * @see com.novell.service.file.nw.DirectoryEntryInformation#ATTRIBUTE_ID
    */
   public String getID()
   {
      return(ATTRIBUTE_ID);
   }

   /**
    * Compares the object in the search string component with this static
    * attribute value.
    *
    * <p>This method will compare the value object against this static
    * attribute value's current value, in the manner specified in the
    * search string component, and return the result of this compare.
    * </p>
    *
    * @param ssc                 The search string component to use for the
    *                            compare.
    * @return                    true if the operation compares true, false
    *                            otherwise.
    *
    * @exception InvalidSearchFilterException When the search filter
    *                            is invalid.
    */
   public boolean compare(SearchStringComponent ssc)
      throws NamingException
   {
      try
      {
         return equals(ssc);
      } catch (IllegalArgumentException e)
      {
         InvalidSearchFilterException isfe =
            new InvalidSearchFilterException();

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

   /**
    * Compares the object in the search string component with this static
    * attribute value.
    *
    * <p>This method will compare the value object against this static
    * attribute value's current value, in the manner specified in the
    * search string component, and return the result of this compare.
    * </p>
    *
    * @param ssc                 The search string component to use for the
    *                            compare.
    * @return                    true if the operation compares true, false
    *                            otherwise.
    *
    * @exception NSIException If refresh fails.
    * @exception IllegalArgumentException If the search string component
    *                            operation type is not supported.
    */
   public boolean equals(SearchStringComponent ssc)
   {
      if (ssc == null)
         return false;

      int type = ssc.getOperationType();

      if (type == ssc.PRESENT)
         return true;

      if (type != ssc.EQUALS && type != ssc.SUBSTRING)
         return false;

      EffectiveRights efr = null;
      String name = null;
      boolean nameOnly = true;
      if (ssc.operandReplacement())
      {
         efr = (EffectiveRights) ssc.getReplacementObject();
         if (efr == null)
            throw new IllegalArgumentException(ssc.getOperation());
         synchronized(efr)
         {
            name = efr.getUser();
         }
         nameOnly = false;
      }else
         name = ssc.getOperand();

      refresh();
      if (type == ssc.EQUALS)
      {
         if (nameOnly)
            return name.equalsIgnoreCase(getUser());
         try
         {
            synchronized(efr)
            {
               return equals(efr);
            }
         } catch (Exception e)
         {
            return false;
         }
      }

      if (type == ssc.SUBSTRING)
      {
         return SearchStringComponent.compareSubString(
                                          name,
                                          getUser(),
                                          true);
      }
      return false;
   }

   /**
    * Returns the static interface object.
    *
    * <p>This method returns the appropriate object for the static interface
    * to this attribute value.
    * </p>
    *
    * @return                    DirectoryEntryInformation.
    *
    */
   public Object getStaticInterface()
   {
     EffectiveRightsImpl efr = null;
     efr = new EffectiveRightsImpl(environment);
      efr.refresh();
      return efr;
   }

   /**
    * Set the User field.
    *
    * <p>Overrides the supers setUser. The super is simply called and then
    * a refresh is executed to update the state of the object.  This allows
    * the jndi dynamic method to obtain an EffectiveRights object through the
    * dynamic getattributes method, and then specify the user to obtain 
    * effective rights information on.  The originally returned object to
    * jndi will has the effective rights of the currently logged user.
    * </p>
    *
    * @param value               The User to obtain the effective rights for.
    */
   public void setUser(String value)
   {
      super.setUser(value);
      refresh();
   }


/* **************************************************************************
   state update methods
****************************************************************************/

   /**
    * Refreshes the state of this static attribute value.
    *
    * <p>Causes the data to be retrieved from the Netware server.
    * </p>
    *
    * @exception  NSIException   When an error occurs reading the data
    *                            from the server.
    */
   public void refresh()
      throws NSIException
   {
      int ccode;

      try
      {
         int rightsValue[] = new int[1];
         if (userWasSet)
         {
            // user was specified, use the getObjectEffectiveRights method
            userId = ObjectNameImpl.nameToObjectId(
                                             user,
                                             callsService,
                                             netService,
                                             sessionIsNDS);

            String fullPath = fullNodeName;

            if (fullPath.indexOf(':') == -1)
               fullPath = fullPath + ":";

            callsService.getObjectEffectiveRights(
                  userId,
                  0,
                  fullPath,
                  NameSpace.nameToNumber(nameSpace),
                  rightsValue);

            rights = rightsValue[0];

            return;
         }
         // user was not set use the getEffectiveRights method (current logged user)

         callsService.getEffectiveRights(
               0,
               fullNodeName,
               NameSpace.nameToNumber(nameSpace),
               rightsValue);

         rights = rightsValue[0];

         // set the user for them, it is the default logged user
         user = (String) environment.getSession().
               getAttributes(
                  new String[] {XplatSession.USER_NAME_ATTR_ID}).
                     getValue(XplatSession.USER_NAME_ATTR_ID);
      }

      catch (SessionException e)
      {
         throw new NSIException(e.getMessage(), 0, e);
      }
      catch (NamingException ne)
      {
         throw new NSIException(ne.getMessage(), 0, ne);
      }
   }

   /**
    * Modify this static attribute value's server-side data using
    * the data provided in the specified directory entry information object.
    *
    * @exception  NSIException   When an error occurs setting the data
    *                            to the server.
    */

   public void modify(EffectiveRights info)
      throws NSIException
   {
      throw new NSIException();
   }
}
