Save This Page
Home » openjdk-7 » javax » naming » directory » [javadoc | source]
    1   /*
    2    * Copyright 1999-2004 Sun Microsystems, Inc.  All Rights Reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Sun designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Sun in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
   22    * CA 95054 USA or visit www.sun.com if you need additional information or
   23    * have any questions.
   24    */
   25   
   26   package javax.naming.directory;
   27   
   28   import java.util.Vector;
   29   import java.util.Enumeration;
   30   import java.util.NoSuchElementException;
   31   import java.lang.reflect.Array;
   32   
   33   import javax.naming.NamingException;
   34   import javax.naming.NamingEnumeration;
   35   import javax.naming.OperationNotSupportedException;
   36   
   37   /**
   38     * This class provides a basic implementation of the <tt>Attribute</tt> interface.
   39     *<p>
   40     * This implementation does not support the schema methods
   41     * <tt>getAttributeDefinition()</tt> and <tt>getAttributeSyntaxDefinition()</tt>.
   42     * They simply throw <tt>OperationNotSupportedException</tt>.
   43     * Subclasses of <tt>BasicAttribute</tt> should override these methods if they
   44     * support them.
   45     *<p>
   46     * The <tt>BasicAttribute</tt> class by default uses <tt>Object.equals()</tt> to
   47     * determine equality of attribute values when testing for equality or
   48     * when searching for values, <em>except</em> when the value is an array.
   49     * For an array, each element of the array is checked using <tt>Object.equals()</tt>.
   50     * Subclasses of <tt>BasicAttribute</tt> can make use of schema information
   51     * when doing similar equality checks by overriding methods
   52     * in which such use of schema is meaningful.
   53     * Similarly, the <tt>BasicAttribute</tt> class by default returns the values passed to its
   54     * constructor and/or manipulated using the add/remove methods.
   55     * Subclasses of <tt>BasicAttribute</tt> can override <tt>get()</tt> and <tt>getAll()</tt>
   56     * to get the values dynamically from the directory (or implement
   57     * the <tt>Attribute</tt> interface directly instead of subclassing <tt>BasicAttribute</tt>).
   58     *<p>
   59     * Note that updates to <tt>BasicAttribute</tt> (such as adding or removing a value)
   60     * does not affect the corresponding representation of the attribute
   61     * in the directory.  Updates to the directory can only be effected
   62     * using operations in the <tt>DirContext</tt> interface.
   63     *<p>
   64     * A <tt>BasicAttribute</tt> instance is not synchronized against concurrent
   65     * multithreaded access. Multiple threads trying to access and modify a
   66     * <tt>BasicAttribute</tt> should lock the object.
   67     *
   68     * @author Rosanna Lee
   69     * @author Scott Seligman
   70     * @since 1.3
   71     */
   72   public class BasicAttribute implements Attribute {
   73       /**
   74        * Holds the attribute's id. It is initialized by the public constructor and
   75        * cannot be null unless methods in BasicAttribute that use attrID
   76        * have been overridden.
   77        * @serial
   78        */
   79       protected String attrID;
   80   
   81       /**
   82        * Holds the attribute's values. Initialized by public constructors.
   83        * Cannot be null unless methods in BasicAttribute that use
   84        * values have been overridden.
   85        */
   86       protected transient Vector<Object> values;
   87   
   88       /**
   89        * A flag for recording whether this attribute's values are ordered.
   90        * @serial
   91        */
   92       protected boolean ordered = false;
   93   
   94       public Object clone() {
   95           BasicAttribute attr;
   96           try {
   97               attr = (BasicAttribute)super.clone();
   98           } catch (CloneNotSupportedException e) {
   99               attr = new BasicAttribute(attrID, ordered);
  100           }
  101           attr.values = (Vector)values.clone();
  102           return attr;
  103       }
  104   
  105       /**
  106         * Determines whether obj is equal to this attribute.
  107         * Two attributes are equal if their attribute-ids, syntaxes
  108         * and values are equal.
  109         * If the attribute values are unordered, the order that the values were added
  110         * are irrelevant. If the attribute values are ordered, then the
  111         * order the values must match.
  112         * If obj is null or not an Attribute, false is returned.
  113         *<p>
  114         * By default <tt>Object.equals()</tt> is used when comparing the attribute
  115         * id and its values except when a value is an array. For an array,
  116         * each element of the array is checked using <tt>Object.equals()</tt>.
  117         * A subclass may override this to make
  118         * use of schema syntax information and matching rules,
  119         * which define what it means for two attributes to be equal.
  120         * How and whether a subclass makes
  121         * use of the schema information is determined by the subclass.
  122         * If a subclass overrides <tt>equals()</tt>, it should also override
  123         * <tt>hashCode()</tt>
  124         * such that two attributes that are equal have the same hash code.
  125         *
  126         * @param obj      The possibly null object to check.
  127         * @return true if obj is equal to this attribute; false otherwise.
  128         * @see #hashCode
  129         * @see #contains
  130         */
  131       public boolean equals(Object obj) {
  132           if ((obj != null) && (obj instanceof Attribute)) {
  133               Attribute target = (Attribute)obj;
  134   
  135               // Check order first
  136               if (isOrdered() != target.isOrdered()) {
  137                   return false;
  138               }
  139               int len;
  140               if (attrID.equals(target.getID()) &&
  141                   (len=size()) == target.size()) {
  142                   try {
  143                       if (isOrdered()) {
  144                           // Go through both list of values
  145                           for (int i = 0; i < len; i++) {
  146                               if (!valueEquals(get(i), target.get(i))) {
  147                                   return false;
  148                               }
  149                           }
  150                       } else {
  151                           // order is not relevant; check for existence
  152                           Enumeration theirs = target.getAll();
  153                           while (theirs.hasMoreElements()) {
  154                               if (find(theirs.nextElement()) < 0)
  155                                   return false;
  156                           }
  157                       }
  158                   } catch (NamingException e) {
  159                       return false;
  160                   }
  161                   return true;
  162               }
  163           }
  164           return false;
  165       }
  166   
  167       /**
  168         * Calculates the hash code of this attribute.
  169         *<p>
  170         * The hash code is computed by adding the hash code of
  171         * the attribute's id and that of all of its values except for
  172         * values that are arrays.
  173         * For an array, the hash code of each element of the array is summed.
  174         * If a subclass overrides <tt>hashCode()</tt>, it should override
  175         * <tt>equals()</tt>
  176         * as well so that two attributes that are equal have the same hash code.
  177         *
  178         * @return an int representing the hash code of this attribute.
  179         * @see #equals
  180         */
  181       public int hashCode() {
  182           int hash = attrID.hashCode();
  183           int num = values.size();
  184           Object val;
  185           for (int i = 0; i < num; i ++) {
  186               val = values.elementAt(i);
  187               if (val != null) {
  188                   if (val.getClass().isArray()) {
  189                       Object it;
  190                       int len = Array.getLength(val);
  191                       for (int j = 0 ; j < len ; j++) {
  192                           it = Array.get(val, j);
  193                           if (it != null) {
  194                               hash += it.hashCode();
  195                           }
  196                       }
  197                   } else {
  198                       hash += val.hashCode();
  199                   }
  200               }
  201           }
  202           return hash;
  203       }
  204   
  205       /**
  206         * Generates the string representation of this attribute.
  207         * The string consists of the attribute's id and its values.
  208         * This string is meant for debugging and not meant to be
  209         * interpreted programmatically.
  210         * @return The non-null string representation of this attribute.
  211         */
  212       public String toString() {
  213           StringBuffer answer = new StringBuffer(attrID + ": ");
  214           if (values.size() == 0) {
  215               answer.append("No values");
  216           } else {
  217               boolean start = true;
  218               for (Enumeration e = values.elements(); e.hasMoreElements(); ) {
  219                   if (!start)
  220                       answer.append(", ");
  221                   answer.append(e.nextElement());
  222                   start = false;
  223               }
  224           }
  225           return answer.toString();
  226       }
  227   
  228       /**
  229         * Constructs a new instance of an unordered attribute with no value.
  230         *
  231         * @param id The attribute's id. It cannot be null.
  232         */
  233       public BasicAttribute(String id) {
  234           this(id, false);
  235       }
  236   
  237       /**
  238         * Constructs a new instance of an unordered attribute with a single value.
  239         *
  240         * @param id The attribute's id. It cannot be null.
  241         * @param value The attribute's value. If null, a null
  242         *        value is added to the attribute.
  243         */
  244       public BasicAttribute(String id, Object value) {
  245           this(id, value, false);
  246       }
  247   
  248       /**
  249         * Constructs a new instance of a possibly ordered attribute with no value.
  250         *
  251         * @param id The attribute's id. It cannot be null.
  252         * @param ordered true means the attribute's values will be ordered;
  253         * false otherwise.
  254         */
  255       public BasicAttribute(String id, boolean ordered) {
  256           attrID = id;
  257           values = new Vector();
  258           this.ordered = ordered;
  259       }
  260   
  261       /**
  262         * Constructs a new instance of a possibly ordered attribute with a
  263         * single value.
  264         *
  265         * @param id The attribute's id. It cannot be null.
  266         * @param value The attribute's value. If null, a null
  267         *        value is added to the attribute.
  268         * @param ordered true means the attribute's values will be ordered;
  269         * false otherwise.
  270         */
  271       public BasicAttribute(String id, Object value, boolean ordered) {
  272           this(id, ordered);
  273           values.addElement(value);
  274       }
  275   
  276       /**
  277         * Retrieves an enumeration of this attribute's values.
  278         *<p>
  279         * By default, the values returned are those passed to the
  280         * constructor and/or manipulated using the add/replace/remove methods.
  281         * A subclass may override this to retrieve the values dynamically
  282         * from the directory.
  283         */
  284       public NamingEnumeration<?> getAll() throws NamingException {
  285         return new ValuesEnumImpl();
  286       }
  287   
  288       /**
  289         * Retrieves one of this attribute's values.
  290         *<p>
  291         * By default, the value returned is one of those passed to the
  292         * constructor and/or manipulated using the add/replace/remove methods.
  293         * A subclass may override this to retrieve the value dynamically
  294         * from the directory.
  295         */
  296       public Object get() throws NamingException {
  297           if (values.size() == 0) {
  298               throw new
  299           NoSuchElementException("Attribute " + getID() + " has no value");
  300           } else {
  301               return values.elementAt(0);
  302           }
  303       }
  304   
  305       public int size() {
  306         return values.size();
  307       }
  308   
  309       public String getID() {
  310           return attrID;
  311       }
  312   
  313       /**
  314         * Determines whether a value is in this attribute.
  315         *<p>
  316         * By default,
  317         * <tt>Object.equals()</tt> is used when comparing <tt>attrVal</tt>
  318         * with this attribute's values except when <tt>attrVal</tt> is an array.
  319         * For an array, each element of the array is checked using
  320         * <tt>Object.equals()</tt>.
  321         * A subclass may use schema information to determine equality.
  322         */
  323       public boolean contains(Object attrVal) {
  324           return (find(attrVal) >= 0);
  325       }
  326   
  327       // For finding first element that has a null in JDK1.1 Vector.
  328       // In the Java 2 platform, can just replace this with Vector.indexOf(target);
  329       private int find(Object target) {
  330           Class cl;
  331           if (target == null) {
  332               int ct = values.size();
  333               for (int i = 0 ; i < ct ; i++) {
  334                   if (values.elementAt(i) == null)
  335                       return i;
  336               }
  337           } else if ((cl=target.getClass()).isArray()) {
  338               int ct = values.size();
  339               Object it;
  340               for (int i = 0 ; i < ct ; i++) {
  341                   it = values.elementAt(i);
  342                   if (it != null && cl == it.getClass()
  343                       && arrayEquals(target, it))
  344                       return i;
  345               }
  346           } else {
  347               return values.indexOf(target, 0);
  348           }
  349           return -1;  // not found
  350       }
  351   
  352       /**
  353        * Determines whether two attribute values are equal.
  354        * Use arrayEquals for arrays and <tt>Object.equals()</tt> otherwise.
  355        */
  356       private static boolean valueEquals(Object obj1, Object obj2) {
  357           if (obj1 == obj2) {
  358               return true; // object references are equal
  359           }
  360           if (obj1 == null) {
  361               return false; // obj2 was not false
  362           }
  363           if (obj1.getClass().isArray() &&
  364               obj2.getClass().isArray()) {
  365               return arrayEquals(obj1, obj2);
  366           }
  367           return (obj1.equals(obj2));
  368       }
  369   
  370       /**
  371        * Determines whether two arrays are equal by comparing each of their
  372        * elements using <tt>Object.equals()</tt>.
  373        */
  374       private static boolean arrayEquals(Object a1, Object a2) {
  375           int len;
  376           if ((len = Array.getLength(a1)) != Array.getLength(a2))
  377               return false;
  378   
  379           for (int j = 0; j < len; j++) {
  380               Object i1 = Array.get(a1, j);
  381               Object i2 = Array.get(a2, j);
  382               if (i1 == null || i2 == null) {
  383                   if (i1 != i2)
  384                       return false;
  385               } else if (!i1.equals(i2)) {
  386                   return false;
  387               }
  388           }
  389           return true;
  390       }
  391   
  392       /**
  393         * Adds a new value to this attribute.
  394         *<p>
  395         * By default, <tt>Object.equals()</tt> is used when comparing <tt>attrVal</tt>
  396         * with this attribute's values except when <tt>attrVal</tt> is an array.
  397         * For an array, each element of the array is checked using
  398         * <tt>Object.equals()</tt>.
  399         * A subclass may use schema information to determine equality.
  400         */
  401       public boolean add(Object attrVal) {
  402           if (isOrdered() || (find(attrVal) < 0)) {
  403               values.addElement(attrVal);
  404               return true;
  405           } else {
  406               return false;
  407           }
  408       }
  409   
  410       /**
  411         * Removes a specified value from this attribute.
  412         *<p>
  413         * By default, <tt>Object.equals()</tt> is used when comparing <tt>attrVal</tt>
  414         * with this attribute's values except when <tt>attrVal</tt> is an array.
  415         * For an array, each element of the array is checked using
  416         * <tt>Object.equals()</tt>.
  417         * A subclass may use schema information to determine equality.
  418         */
  419       public boolean remove(Object attrval) {
  420           // For the Java 2 platform, can just use "return removeElement(attrval);"
  421           // Need to do the following to handle null case
  422   
  423           int i = find(attrval);
  424           if (i >= 0) {
  425               values.removeElementAt(i);
  426               return true;
  427           }
  428           return false;
  429       }
  430   
  431       public void clear() {
  432           values.setSize(0);
  433       }
  434   
  435   //  ---- ordering methods
  436   
  437       public boolean isOrdered() {
  438           return ordered;
  439       }
  440   
  441       public Object get(int ix) throws NamingException {
  442           return values.elementAt(ix);
  443       }
  444   
  445       public Object remove(int ix) {
  446           Object answer = values.elementAt(ix);
  447           values.removeElementAt(ix);
  448           return answer;
  449       }
  450   
  451       public void add(int ix, Object attrVal) {
  452           if (!isOrdered() && contains(attrVal)) {
  453               throw new IllegalStateException(
  454                   "Cannot add duplicate to unordered attribute");
  455           }
  456           values.insertElementAt(attrVal, ix);
  457       }
  458   
  459       public Object set(int ix, Object attrVal) {
  460           if (!isOrdered() && contains(attrVal)) {
  461               throw new IllegalStateException(
  462                   "Cannot add duplicate to unordered attribute");
  463           }
  464   
  465           Object answer = values.elementAt(ix);
  466           values.setElementAt(attrVal, ix);
  467           return answer;
  468       }
  469   
  470   // ----------------- Schema methods
  471   
  472       /**
  473         * Retrieves the syntax definition associated with this attribute.
  474         *<p>
  475         * This method by default throws OperationNotSupportedException. A subclass
  476         * should override this method if it supports schema.
  477         */
  478       public DirContext getAttributeSyntaxDefinition() throws NamingException {
  479               throw new OperationNotSupportedException("attribute syntax");
  480       }
  481   
  482       /**
  483         * Retrieves this attribute's schema definition.
  484         *<p>
  485         * This method by default throws OperationNotSupportedException. A subclass
  486         * should override this method if it supports schema.
  487         */
  488       public DirContext getAttributeDefinition() throws NamingException {
  489           throw new OperationNotSupportedException("attribute definition");
  490       }
  491   
  492   
  493   //  ---- serialization methods
  494   
  495       /**
  496        * Overridden to avoid exposing implementation details
  497        * @serialData Default field (the attribute ID -- a String),
  498        * followed by the number of values (an int), and the
  499        * individual values.
  500        */
  501       private void writeObject(java.io.ObjectOutputStream s)
  502               throws java.io.IOException {
  503           s.defaultWriteObject(); // write out the attrID
  504           s.writeInt(values.size());
  505           for (int i = 0; i < values.size(); i++) {
  506               s.writeObject(values.elementAt(i));
  507           }
  508       }
  509   
  510       /**
  511        * Overridden to avoid exposing implementation details.
  512        */
  513       private void readObject(java.io.ObjectInputStream s)
  514               throws java.io.IOException, ClassNotFoundException {
  515           s.defaultReadObject();  // read in the attrID
  516           int n = s.readInt();    // number of values
  517           values = new Vector(n);
  518           while (--n >= 0) {
  519               values.addElement(s.readObject());
  520           }
  521       }
  522   
  523   
  524       class ValuesEnumImpl implements NamingEnumeration<Object> {
  525       Enumeration list;
  526   
  527       ValuesEnumImpl() {
  528           list = values.elements();
  529       }
  530   
  531       public boolean hasMoreElements() {
  532           return list.hasMoreElements();
  533       }
  534   
  535       public Object nextElement() {
  536           return(list.nextElement());
  537       }
  538   
  539       public Object next() throws NamingException {
  540           return list.nextElement();
  541       }
  542   
  543       public boolean hasMore() throws NamingException {
  544           return list.hasMoreElements();
  545       }
  546   
  547       public void close() throws NamingException {
  548           list = null;
  549       }
  550       }
  551   
  552       /**
  553        * Use serialVersionUID from JNDI 1.1.1 for interoperability.
  554        */
  555       private static final long serialVersionUID = 6743528196119291326L;
  556   }

Save This Page
Home » openjdk-7 » javax » naming » directory » [javadoc | source]