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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * 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; 95 public Object clone() { 96 BasicAttribute attr; 97 try { 98 attr = (BasicAttribute)super.clone(); 99 } catch (CloneNotSupportedException e) { 100 attr = new BasicAttribute(attrID, ordered); 101 } 102 attr.values = (Vector<Object>)values.clone(); 103 return attr; 104 } 105 106 /** 107 * Determines whether obj is equal to this attribute. 108 * Two attributes are equal if their attribute-ids, syntaxes 109 * and values are equal. 110 * If the attribute values are unordered, the order that the values were added 111 * are irrelevant. If the attribute values are ordered, then the 112 * order the values must match. 113 * If obj is null or not an Attribute, false is returned. 114 *<p> 115 * By default <tt>Object.equals()</tt> is used when comparing the attribute 116 * id and its values except when a value is an array. For an array, 117 * each element of the array is checked using <tt>Object.equals()</tt>. 118 * A subclass may override this to make 119 * use of schema syntax information and matching rules, 120 * which define what it means for two attributes to be equal. 121 * How and whether a subclass makes 122 * use of the schema information is determined by the subclass. 123 * If a subclass overrides <tt>equals()</tt>, it should also override 124 * <tt>hashCode()</tt> 125 * such that two attributes that are equal have the same hash code. 126 * 127 * @param obj The possibly null object to check. 128 * @return true if obj is equal to this attribute; false otherwise. 129 * @see #hashCode 130 * @see #contains 131 */ 132 public boolean equals(Object obj) { 133 if ((obj != null) && (obj instanceof Attribute)) { 134 Attribute target = (Attribute)obj; 135 136 // Check order first 137 if (isOrdered() != target.isOrdered()) { 138 return false; 139 } 140 int len; 141 if (attrID.equals(target.getID()) && 142 (len=size()) == target.size()) { 143 try { 144 if (isOrdered()) { 155 if (find(theirs.nextElement()) < 0) 156 return false; 157 } 158 } 159 } catch (NamingException e) { 160 return false; 161 } 162 return true; 163 } 164 } 165 return false; 166 } 167 168 /** 169 * Calculates the hash code of this attribute. 170 *<p> 171 * The hash code is computed by adding the hash code of 172 * the attribute's id and that of all of its values except for 173 * values that are arrays. 174 * For an array, the hash code of each element of the array is summed. 175 * If a subclass overrides <tt>hashCode()</tt>, it should override 176 * <tt>equals()</tt> 177 * as well so that two attributes that are equal have the same hash code. 178 * 179 * @return an int representing the hash code of this attribute. 180 * @see #equals 181 */ 182 public int hashCode() { 183 int hash = attrID.hashCode(); 184 int num = values.size(); 185 Object val; 186 for (int i = 0; i < num; i ++) { 187 val = values.elementAt(i); 188 if (val != null) { 189 if (val.getClass().isArray()) { 190 Object it; 191 int len = Array.getLength(val); 192 for (int j = 0 ; j < len ; j++) { 193 it = Array.get(val, j); 194 if (it != null) { 195 hash += it.hashCode(); 196 } 298 if (values.size() == 0) { 299 throw new 300 NoSuchElementException("Attribute " + getID() + " has no value"); 301 } else { 302 return values.elementAt(0); 303 } 304 } 305 306 public int size() { 307 return values.size(); 308 } 309 310 public String getID() { 311 return attrID; 312 } 313 314 /** 315 * Determines whether a value is in this attribute. 316 *<p> 317 * By default, 318 * <tt>Object.equals()</tt> is used when comparing <tt>attrVal</tt> 319 * with this attribute's values except when <tt>attrVal</tt> is an array. 320 * For an array, each element of the array is checked using 321 * <tt>Object.equals()</tt>. 322 * A subclass may use schema information to determine equality. 323 */ 324 public boolean contains(Object attrVal) { 325 return (find(attrVal) >= 0); 326 } 327 328 // For finding first element that has a null in JDK1.1 Vector. 329 // In the Java 2 platform, can just replace this with Vector.indexOf(target); 330 private int find(Object target) { 331 Class<?> cl; 332 if (target == null) { 333 int ct = values.size(); 334 for (int i = 0 ; i < ct ; i++) { 335 if (values.elementAt(i) == null) 336 return i; 337 } 338 } else if ((cl=target.getClass()).isArray()) { 339 int ct = values.size(); 340 Object it; 341 for (int i = 0 ; i < ct ; i++) { 342 it = values.elementAt(i); 343 if (it != null && cl == it.getClass() 344 && arrayEquals(target, it)) 345 return i; 346 } 347 } else { 348 return values.indexOf(target, 0); 349 } 350 return -1; // not found 351 } 352 353 /** 354 * Determines whether two attribute values are equal. 355 * Use arrayEquals for arrays and <tt>Object.equals()</tt> otherwise. 356 */ 357 private static boolean valueEquals(Object obj1, Object obj2) { 358 if (obj1 == obj2) { 359 return true; // object references are equal 360 } 361 if (obj1 == null) { 362 return false; // obj2 was not false 363 } 364 if (obj1.getClass().isArray() && 365 obj2.getClass().isArray()) { 366 return arrayEquals(obj1, obj2); 367 } 368 return (obj1.equals(obj2)); 369 } 370 371 /** 372 * Determines whether two arrays are equal by comparing each of their 373 * elements using <tt>Object.equals()</tt>. 374 */ 375 private static boolean arrayEquals(Object a1, Object a2) { 376 int len; 377 if ((len = Array.getLength(a1)) != Array.getLength(a2)) 378 return false; 379 380 for (int j = 0; j < len; j++) { 381 Object i1 = Array.get(a1, j); 382 Object i2 = Array.get(a2, j); 383 if (i1 == null || i2 == null) { 384 if (i1 != i2) 385 return false; 386 } else if (!i1.equals(i2)) { 387 return false; 388 } 389 } 390 return true; 391 } 392 393 /** 394 * Adds a new value to this attribute. 395 *<p> 396 * By default, <tt>Object.equals()</tt> is used when comparing <tt>attrVal</tt> 397 * with this attribute's values except when <tt>attrVal</tt> is an array. 398 * For an array, each element of the array is checked using 399 * <tt>Object.equals()</tt>. 400 * A subclass may use schema information to determine equality. 401 */ 402 public boolean add(Object attrVal) { 403 if (isOrdered() || (find(attrVal) < 0)) { 404 values.addElement(attrVal); 405 return true; 406 } else { 407 return false; 408 } 409 } 410 411 /** 412 * Removes a specified value from this attribute. 413 *<p> 414 * By default, <tt>Object.equals()</tt> is used when comparing <tt>attrVal</tt> 415 * with this attribute's values except when <tt>attrVal</tt> is an array. 416 * For an array, each element of the array is checked using 417 * <tt>Object.equals()</tt>. 418 * A subclass may use schema information to determine equality. 419 */ 420 public boolean remove(Object attrval) { 421 // For the Java 2 platform, can just use "return removeElement(attrval);" 422 // Need to do the following to handle null case 423 424 int i = find(attrval); 425 if (i >= 0) { 426 values.removeElementAt(i); 427 return true; 428 } 429 return false; 430 } 431 432 public void clear() { 433 values.setSize(0); 434 } 435 436 // ---- ordering methods 437 | 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * 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 {@code Attribute} interface. 39 *<p> 40 * This implementation does not support the schema methods 41 * {@code getAttributeDefinition()} and {@code getAttributeSyntaxDefinition()}. 42 * They simply throw {@code OperationNotSupportedException}. 43 * Subclasses of {@code BasicAttribute} should override these methods if they 44 * support them. 45 *<p> 46 * The {@code BasicAttribute} class by default uses {@code Object.equals()} 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 {@code Object.equals()}. 50 * Subclasses of {@code BasicAttribute} 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 {@code BasicAttribute} class by default returns the values passed to its 54 * constructor and/or manipulated using the add/remove methods. 55 * Subclasses of {@code BasicAttribute} can override {@code get()} and {@code getAll()} 56 * to get the values dynamically from the directory (or implement 57 * the {@code Attribute} interface directly instead of subclassing {@code BasicAttribute}). 58 *<p> 59 * Note that updates to {@code BasicAttribute} (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 {@code DirContext} interface. 63 *<p> 64 * A {@code BasicAttribute} instance is not synchronized against concurrent 65 * multithreaded access. Multiple threads trying to access and modify a 66 * {@code BasicAttribute} 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; 95 public Object clone() { 96 BasicAttribute attr; 97 try { 98 attr = (BasicAttribute)super.clone(); 99 } catch (CloneNotSupportedException e) { 100 attr = new BasicAttribute(attrID, ordered); 101 } 102 attr.values = (Vector<Object>)values.clone(); 103 return attr; 104 } 105 106 /** 107 * Determines whether obj is equal to this attribute. 108 * Two attributes are equal if their attribute-ids, syntaxes 109 * and values are equal. 110 * If the attribute values are unordered, the order that the values were added 111 * are irrelevant. If the attribute values are ordered, then the 112 * order the values must match. 113 * If obj is null or not an Attribute, false is returned. 114 *<p> 115 * By default {@code Object.equals()} is used when comparing the attribute 116 * id and its values except when a value is an array. For an array, 117 * each element of the array is checked using {@code Object.equals()}. 118 * A subclass may override this to make 119 * use of schema syntax information and matching rules, 120 * which define what it means for two attributes to be equal. 121 * How and whether a subclass makes 122 * use of the schema information is determined by the subclass. 123 * If a subclass overrides {@code equals()}, it should also override 124 * {@code hashCode()} 125 * such that two attributes that are equal have the same hash code. 126 * 127 * @param obj The possibly null object to check. 128 * @return true if obj is equal to this attribute; false otherwise. 129 * @see #hashCode 130 * @see #contains 131 */ 132 public boolean equals(Object obj) { 133 if ((obj != null) && (obj instanceof Attribute)) { 134 Attribute target = (Attribute)obj; 135 136 // Check order first 137 if (isOrdered() != target.isOrdered()) { 138 return false; 139 } 140 int len; 141 if (attrID.equals(target.getID()) && 142 (len=size()) == target.size()) { 143 try { 144 if (isOrdered()) { 155 if (find(theirs.nextElement()) < 0) 156 return false; 157 } 158 } 159 } catch (NamingException e) { 160 return false; 161 } 162 return true; 163 } 164 } 165 return false; 166 } 167 168 /** 169 * Calculates the hash code of this attribute. 170 *<p> 171 * The hash code is computed by adding the hash code of 172 * the attribute's id and that of all of its values except for 173 * values that are arrays. 174 * For an array, the hash code of each element of the array is summed. 175 * If a subclass overrides {@code hashCode()}, it should override 176 * {@code equals()} 177 * as well so that two attributes that are equal have the same hash code. 178 * 179 * @return an int representing the hash code of this attribute. 180 * @see #equals 181 */ 182 public int hashCode() { 183 int hash = attrID.hashCode(); 184 int num = values.size(); 185 Object val; 186 for (int i = 0; i < num; i ++) { 187 val = values.elementAt(i); 188 if (val != null) { 189 if (val.getClass().isArray()) { 190 Object it; 191 int len = Array.getLength(val); 192 for (int j = 0 ; j < len ; j++) { 193 it = Array.get(val, j); 194 if (it != null) { 195 hash += it.hashCode(); 196 } 298 if (values.size() == 0) { 299 throw new 300 NoSuchElementException("Attribute " + getID() + " has no value"); 301 } else { 302 return values.elementAt(0); 303 } 304 } 305 306 public int size() { 307 return values.size(); 308 } 309 310 public String getID() { 311 return attrID; 312 } 313 314 /** 315 * Determines whether a value is in this attribute. 316 *<p> 317 * By default, 318 * {@code Object.equals()} is used when comparing {@code attrVal} 319 * with this attribute's values except when {@code attrVal} is an array. 320 * For an array, each element of the array is checked using 321 * {@code Object.equals()}. 322 * A subclass may use schema information to determine equality. 323 */ 324 public boolean contains(Object attrVal) { 325 return (find(attrVal) >= 0); 326 } 327 328 // For finding first element that has a null in JDK1.1 Vector. 329 // In the Java 2 platform, can just replace this with Vector.indexOf(target); 330 private int find(Object target) { 331 Class<?> cl; 332 if (target == null) { 333 int ct = values.size(); 334 for (int i = 0 ; i < ct ; i++) { 335 if (values.elementAt(i) == null) 336 return i; 337 } 338 } else if ((cl=target.getClass()).isArray()) { 339 int ct = values.size(); 340 Object it; 341 for (int i = 0 ; i < ct ; i++) { 342 it = values.elementAt(i); 343 if (it != null && cl == it.getClass() 344 && arrayEquals(target, it)) 345 return i; 346 } 347 } else { 348 return values.indexOf(target, 0); 349 } 350 return -1; // not found 351 } 352 353 /** 354 * Determines whether two attribute values are equal. 355 * Use arrayEquals for arrays and {@code Object.equals()} otherwise. 356 */ 357 private static boolean valueEquals(Object obj1, Object obj2) { 358 if (obj1 == obj2) { 359 return true; // object references are equal 360 } 361 if (obj1 == null) { 362 return false; // obj2 was not false 363 } 364 if (obj1.getClass().isArray() && 365 obj2.getClass().isArray()) { 366 return arrayEquals(obj1, obj2); 367 } 368 return (obj1.equals(obj2)); 369 } 370 371 /** 372 * Determines whether two arrays are equal by comparing each of their 373 * elements using {@code Object.equals()}. 374 */ 375 private static boolean arrayEquals(Object a1, Object a2) { 376 int len; 377 if ((len = Array.getLength(a1)) != Array.getLength(a2)) 378 return false; 379 380 for (int j = 0; j < len; j++) { 381 Object i1 = Array.get(a1, j); 382 Object i2 = Array.get(a2, j); 383 if (i1 == null || i2 == null) { 384 if (i1 != i2) 385 return false; 386 } else if (!i1.equals(i2)) { 387 return false; 388 } 389 } 390 return true; 391 } 392 393 /** 394 * Adds a new value to this attribute. 395 *<p> 396 * By default, {@code Object.equals()} is used when comparing {@code attrVal} 397 * with this attribute's values except when {@code attrVal} is an array. 398 * For an array, each element of the array is checked using 399 * {@code Object.equals()}. 400 * A subclass may use schema information to determine equality. 401 */ 402 public boolean add(Object attrVal) { 403 if (isOrdered() || (find(attrVal) < 0)) { 404 values.addElement(attrVal); 405 return true; 406 } else { 407 return false; 408 } 409 } 410 411 /** 412 * Removes a specified value from this attribute. 413 *<p> 414 * By default, {@code Object.equals()} is used when comparing {@code attrVal} 415 * with this attribute's values except when {@code attrVal} is an array. 416 * For an array, each element of the array is checked using 417 * {@code Object.equals()}. 418 * A subclass may use schema information to determine equality. 419 */ 420 public boolean remove(Object attrval) { 421 // For the Java 2 platform, can just use "return removeElement(attrval);" 422 // Need to do the following to handle null case 423 424 int i = find(attrval); 425 if (i >= 0) { 426 values.removeElementAt(i); 427 return true; 428 } 429 return false; 430 } 431 432 public void clear() { 433 values.setSize(0); 434 } 435 436 // ---- ordering methods 437 |