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

  $Archive: /njcl_v2/src/com/novell/service/file/nw/EffectiveRights.java $
  $Revision: 8 $
  $Modtime: 12/17/99 10:38a $
 
  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;

import com.novell.service.rfc1960.SearchStringComponent;
import com.novell.service.rfc1960.Rfc1960Parser;

/** 
 * Provides an attribute interface for returning the effective rights
 * of a file or a directory.
 *
 * <p>This class contains the following information about the effective
 * rights of a file or directory:
 * <ul>
 * <li>User - The user's name for which to return effective rights
 * (must be bindery super user of requested user).
 * <li>rights - The rights for the currently logged user or the
 * requested user.</ul></p>
 *
 * <p>The jndi.ds.Attribute.getAttributeID() returns Effective Rights
 * as the attribute ID for this interface.
 *
 * <p>This object has a dual mode of operation. The first mode is the 
 * average user wanting to know what their effective rights are on a given 
 * directory entry. The second mode is requesting the effective rights of 
 * some other user on the system. This mode requires that the logged
 * user have management rights (in the bindery) over the user name being 
 * requested. Also, it is enabled by the user setting the user name of
 * the object. 
 * </p>
 * <p>WARNING: This class results in a mutable object. For versatility 
 * code block synchronization has been implemented in the various jndi
 * search and modify methods of this classes implementation to provide
 * for thread safe operation.
 * </p>
 * <p>If you have a multi-threaded application and a code segment of that
 * application uses get methods of this class, and there is a potential 
 * of another thread randomly using corresponding set methods of this class,
 * you should enclose the calls to the get methods in a synchronized code
 * block.
 * </p>
 * <p>If you have a multi-threaded application and a code segment of that
 * application uses set methods of this class, and there is a potential 
 * of another thread randomly using corresponding get methods of this class,
 * you should enclose the calls to the set methods of this class in a 
 * synchronized code block.
 * </p>
 */

public class EffectiveRights implements Cloneable
{
/* **************************************************************************
   jndi naming interface defines
****************************************************************************/

   /**
    * Attribute ID of DirectoryEntryInformation.
    *
    * <p>(ATTRIBUTE_ID = "Entry Information")
    * </p>
    */
   public static final String ATTRIBUTE_ID = "Effective Rights";

   /**
    * Schema Class Definition Name of DirectoryEntryInformation.
    *
    * <p>(SCHEMA_BINDING_NAME = ATTRIBUTE_ID + " Definition")
    * </p>
    */
   public static final String SCHEMA_BINDING_NAME =
         ATTRIBUTE_ID + " Definition";

   /**
    * Schema Syntax of DirectoryEntryInformation.
    *
    * <p>(COMPARE_SYNTAX_STRING = 
    *       "(" +
    *       SearchStringComponent.EQUALS_STRING + "," +
    *       SearchStringComponent.PRESENT_STRING + "," +
    *       SearchStringComponent.SUBSTRING_STRING + 
    *       ")")
    * </p>
    */
   public static final String COMPARE_SYNTAX_STRING =
         new String(
               "(" +
               SearchStringComponent.EQUALS_STRING + "," +
               SearchStringComponent.PRESENT_STRING + "," +
               SearchStringComponent.SUBSTRING_STRING +
               ")");

/* **************************************************************************
   compareString field name defines
****************************************************************************/

   /**
    * Field specifier for searching on rights field.
    *
    * <p>(RIGHTS_FIELD = "Rights")
    * </p>
    * @see #setCompareString
    * @see #equals
    */
   public static final String RIGHTS_FIELD = "Rights";

   /**
    * Field specifier for searching on user field.
    *
    * <p>(USER_FIELD = "User")
    * </p>
    * @see #setCompareString
    * @see #equals
    */
   public static final String USER_FIELD = "User";


/* **************************************************************************
   EffectiveRightsMask mask bits
****************************************************************************/

   /**
    * Netware rights: Cannot read or write.
    *
    * <p>(TA_NONE = 0x0000)
    * </p>
    *
    * @see #getRights
    * @see #setRights
    */
   public static final int TA_NONE = 0x0000;

   /**
    * Netware rights: Can read.
    *
    * <p>(TA_READ = 0x0001)
    * </p>
    *
    * @see #getRights
    * @see #setRights
    */
   public static final int TA_READ = 0x0001;

   /**
    * Netware rights: Can write.
    *
    * <p>(TA_WRITE = 0x0002)
    * </p>
    *
    * @see #getRights
    * @see #setRights
    */
   public static final int TA_WRITE = 0x0002;

   /**
    * Netware rights: Can open existing file (obsolete).
    *
    * <p>(TA_WRITE = 0x0004)
    * </p>
    *
    * @see #getRights
    * @see #setRights
    */
   public static final int TA_OLD_OPEN = 0x0004;

   /**
    * Netware rights: Can create files.
    *
    * <p>(TA_CREATE = 0x0008)
    * </p>
    *
    * @see #getRights
    * @see #setRights
    */
   public static final int TA_CREATE = 0x0008;

   /**
    * Netware rights: Can delete files.
    *
    * <p>(TA_DELETE = 0x0010)
    * </p>
    *
    * @see #getRights
    * @see #setRights
    */
   public static final int TA_DELETE = 0x0010;

   /**
    * Netware rights: Can create and delete subdirectories, and
    * can grant and revoke trustee rights.
    *
    * <p>(TA_OWNERSHIP = 0x0020)
    * </p>
    *
    * @see #getRights
    * @see #setRights
    */
   public static final int TA_OWNERSHIP = 0x0020;

   /**
    * Netware rights: Can search the directory.
    *
    * <p>(TA_SEARCH = 0x0040)
    * </p>
    *
    * @see #getRights
    * @see #setRights
    */
   public static final int TA_SEARCH = 0x0040;

   /**
    * Netware rights: Can modify the file attributes.
    *
    * <p>(TA_MODIFY = 0x0080)
    * </p>
    *
    * @see #getRights
    * @see #setRights
    */
   public static final int TA_MODIFY = 0x0080;

   /**
    * Netware rights: User has supervisor rights.
    *
    * <p>(TA_SUPERVISOR = 0x0100)
    * </p>
    *
    * @see #getRights
    * @see #setRights
    */
   public static final int TA_SUPERVISOR = 0x0100;

   /**
    * Netware rights: Specifies all rights to the directory.
    *
    * <p>(TA_ALL = 0x00FB)
    * </p>
    *
    * @see #getRights
    * @see #setRights
    */
   public static final int TA_ALL = 0x01FF; // used to be 0x1fb

/* **************************************************************************
   DirectoryEntryInformation state data members
****************************************************************************/

   /* attribute state */

  /**
   *@internal
   */
   protected int rights;
  /**
   *@internal
   */
   protected String user;

   // only used by the native
  /**
   *@internal
   */
   protected int userId;
  /**
   *@internal
   */
   protected boolean userWasSet = false;

   private String compareString;
   private Rfc1960Parser ssParser = null;
   private boolean firstParser = true;

/* **************************************************************************
   Constructors
****************************************************************************/

   /**
    * Constructs an EffectiveRights object with all fields set to
    * zero or NULL.
    *
    * @see #setUser
    * @see #setRights
    * @see #getUser
    * @see #getRights
    */
   public EffectiveRights()
   {
      this(0,null);
   }
       
   /**
    * Constructs an EffectiveRights object with a user name, and
    * the rights field is set to zero.
    *
    * @param user The user data member value.
    *
    * @see #setUser
    * @see #setRights
    * @see #getUser
    * @see #getRights
    */

   public EffectiveRights(String user)
   {
      this(0, user);
   }

   /**
    * Constructs an EffectiveRights object with the passed in
    * rights value and the user field set to NULL.
    *
    * @param rights The rights data member value.
    *
    * @see #setUser
    * @see #setRights
    * @see #getUser
    * @see #getRights
    */

   public EffectiveRights(int rights)
   {
      this(rights, null);
   }

   /**
    * Constructs an EffectiveRights object with the rights and
    * user values set.
    * 
    * @param rights The rights data member value.
    * @param user   The user data member value.
    *
    * @see #setUser
    * @see #setRights
    * @see #getUser
    * @see #getRights
    */

   public EffectiveRights(int rights, String user)
   {
      this.rights = rights;
      this.user = user;
   }

/* **************************************************************************
   Public Accessor methods
****************************************************************************/

   /**
    * Returns the effective rights field.
    *
    * @return The effective rights.
    */
   public int getRights()
   {
      return rights;
   }

   /**
    * Sets the effective rights field.
    *
    * @param value The effective rights value.
    */
   public void setRights(int value)
   {
      rights = value;
   }

   /**
    * Returns a reference to this object's User field.
    *
    * @return The User associated with the effective rights.
    */

   public String getUser()
   {
      return user;
   }

   /**
    * Sets the User field of the Attribute.
    *
    * The actual parameter reference will be stored by this object (it will 
    * not be cloned). Later modifications to this reference state will 
    * be reflected in this object. Calling the setUser method on an object
    * returned from a jndi.getAttributes() call will result in obtaining
    * the effective rights for the user that is set.
    *
    * @param value The User for which to set the effective rights.
    */
   public void setUser(String value)
   {
      user = value;
      userWasSet = true;
   }

/* **************************************************************************
 public compareString support methods
****************************************************************************/

   /**
    * Sets the compare string value for the Rights and User fields.
    * 
    * The compare string uses the RFC1960 (LDAP) search string format
    * in individual compares on the Rights and User fields:
    *
    * <p>See the various SearchStringComponent compare methods referenced
    * below for detailed information on the operation types allowed for
    * String and integer data members.
    *
    * <p>The names of these fields have taken the names of their 
    * corresponding methods minus the get or set prefix. Given the
    * following string: <i>"(&(User=*test*)(Rights>=128))"</i>
    *
    * <p>The equals() method returns TRUE if the user has the
    * substring test in it, and the rights are set to be able to
    * modify (TA_MODIFY). If the approximate operator type is used on
    * the Rights field the various bits of the operand value are checked,
    * and if any of them are set, equals will return TRUE.  For example:
    * (Rights~=3) returns TRUE if either the TA_READ or TA_WRITE bits
    * are set, regardless of what other bits might be set.
    *
    * <p>If the string passed in is not a valid RFC1960 formatted string,
    * this method will throw an IllegalArgumentException. If the
    * compareString value is NULL, RFC1960 formated compares will be
    * disabled.</p>
    *
    * @param compareString  The RFC1960 formated search string. NULL 
    *                       disables this compare functionality.
    *
    * @exception IllegalArgumentException when the string passed in is
    *            not a valid RFC1960 formatted string.
    *
    * @see #equals
    * @see DirectoryEntryInformation#SPACEALLOC_FIELD
    */
   public void setCompareString(String compareString)
   {
      firstParser = true;
      if (compareString != null)
      {
         this.compareString = new String(compareString);
         ssParser = new Rfc1960Parser(compareString);
      }else
      {
         this.compareString = null;
         ssParser = null;
      }
   }

   /**
    * Returns the current value of compareString.
    * 
    * @return The current value of compareString.
    *
    * @see Trustee#setCompareString
    */
   public String getCompareString()
   {
      return compareString;
   }

   /**
    *  Returns the RFC1960 Search String parser for the compare string.
    * 
    * <p>Returns a Rfc1960Parser that was instantiated when the compareString
    * was last set by the setCompareString() method.
    * </p>
    *
    * @return The Rfc1960Parser for the current compare String.
    *         Returns NULL if the compare string has not been set.
    */
   public Rfc1960Parser getSearchStringParser()
   {
      if (firstParser)
      {
         firstParser = false;
         return ssParser;
      }else
      {
         if (compareString == null)
            return null;
         return new Rfc1960Parser(compareString);
      }
   }

/* **************************************************************************
* overridden Object methods
****************************************************************************/

   /**
    * Determines if the specified passed in object is equal to this
    * EffectiveRights object.
    * 
    * <p>The input object is compared against this object. If the 
    * input object has a RFC1960 compare string, this method will do
    * the  comparison based on the commands in the compare string.</p>
    *
    * @param obj The object to compare.
    *
    * @return TRUE if equals, false otherwise.
    *
    * @exception IllegalArgumentException If the operationType is
    *            illegal for the data type being compared.
    *
    * @see #setCompareString
    */
   public boolean equals(Object obj)
   {
      if (!(obj instanceof EffectiveRights))
         return false;

      EffectiveRights efr = (EffectiveRights) obj;

      Rfc1960Parser ssp = efr.getSearchStringParser();
      if (ssp == null)
      {
         // do a simple compare

         if (obj == this)
            return true;

         if (rights == efr.getRights() &&
             user.equals(efr.getUser()))
            return true;
         return false;
      }
      while (ssp.hasMoreElements())
      {
         SearchStringComponent ssc = ssp.next();
         String name = ssc.getAttributeId();
         boolean compared = false;

         if (name.equals(RIGHTS_FIELD))
         {
            compared =ssc.compareInt(
                              ssc.getOperationType(), 
                              ssc.operandReplacement() ?
                                 efr.getRights() :
                                 Integer.parseInt(ssc.getOperand()),
                              rights);
         }else
         {
         if (name.equals(USER_FIELD))
         {
            compared = ssc.compareString(
                              ssc.getOperationType(), 
                              ssc.operandReplacement() ?
                                 efr.getUser() :
                                 ssc.getOperand(),
                              user,
                              true);
         }else
            compared = false;

         }
         ssp.setCompareResult(ssc, compared);
      }
      return ssp.compared();
   }

   /**
    * Creates and returns a comma separated list of all attribute
    * values. The list returned is in the following format:
    * "rights: n, user: s".</p>
    *
    * @return A Comma separated list of values.
    */
   public String toString()
   {
      return new String(
                     "rights: " + rights +
                     ", user: " + user);
   }

   /**
    * Clones this object.
    * 
    * <p>clone() instantiates a new instance of this type and assigns
    * all fields using the current values of the fields in this
    * directory entry information object.
    * </p>
    *
    * @return A new VolumeRestriction object with the same values.
    */
   public Object clone()
   {
      EffectiveRights obj = null;
      try
      {
         obj = (EffectiveRights) super.clone();
      }
      catch (CloneNotSupportedException e)
      {
         // this shouldn't happen, since we are Cloneable
         throw (new InternalError());
      }

      obj.rights = rights;
      obj.user = user;
      return obj;
   }
}