KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > naming > directory > BasicAttribute


1 /*
2  * @(#)BasicAttribute.java 1.13 04/05/05
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package javax.naming.directory;
9
10 import java.util.Vector JavaDoc;
11 import java.util.Enumeration JavaDoc;
12 import java.util.NoSuchElementException JavaDoc;
13 import java.lang.reflect.Array JavaDoc;
14
15 import javax.naming.NamingException JavaDoc;
16 import javax.naming.NamingEnumeration JavaDoc;
17 import javax.naming.OperationNotSupportedException JavaDoc;
18
19 /**
20   * This class provides a basic implementation of the <tt>Attribute</tt> interface.
21   *<p>
22   * This implementation does not support the schema methods
23   * <tt>getAttributeDefinition()</tt> and <tt>getAttributeSyntaxDefinition()</tt>.
24   * They simply throw <tt>OperationNotSupportedException</tt>.
25   * Subclasses of <tt>BasicAttribute</tt> should override these methods if they
26   * support them.
27   *<p>
28   * The <tt>BasicAttribute</tt> class by default uses <tt>Object.equals()</tt> to
29   * determine equality of attribute values when testing for equality or
30   * when searching for values, <em>except</em> when the value is an array.
31   * For an array, each element of the array is checked using <tt>Object.equals()</tt>.
32   * Subclasses of <tt>BasicAttribute</tt> can make use of schema information
33   * when doing similar equality checks by overriding methods
34   * in which such use of schema is meaningful.
35   * Similarly, the <tt>BasicAttribute</tt> class by default returns the values passed to its
36   * constructor and/or manipulated using the add/remove methods.
37   * Subclasses of <tt>BasicAttribute</tt> can override <tt>get()</tt> and <tt>getAll()</tt>
38   * to get the values dynamically from the directory (or implement
39   * the <tt>Attribute</tt> interface directly instead of subclassing <tt>BasicAttribute</tt>).
40   *<p>
41   * Note that updates to <tt>BasicAttribute</tt> (such as adding or removing a value)
42   * does not affect the corresponding representation of the attribute
43   * in the directory. Updates to the directory can only be effected
44   * using operations in the <tt>DirContext</tt> interface.
45   *<p>
46   * A <tt>BasicAttribute</tt> instance is not synchronized against concurrent
47   * multithreaded access. Multiple threads trying to access and modify a
48   * <tt>BasicAttribute</tt> should lock the object.
49   *
50   * @author Rosanna Lee
51   * @author Scott Seligman
52   * @version 1.13 04/05/05
53   * @since 1.3
54   */

55 public class BasicAttribute implements Attribute JavaDoc {
56     /**
57      * Holds the attribute's id. It is initialized by the public constructor and
58      * cannot be null unless methods in BasicAttribute that use attrID
59      * have been overridden.
60      * @serial
61      */

62     protected String JavaDoc attrID;
63
64     /**
65      * Holds the attribute's values. Initialized by public constructors.
66      * Cannot be null unless methods in BasicAttribute that use
67      * values have been overridden.
68      */

69     protected transient Vector JavaDoc<Object JavaDoc> values;
70
71     /**
72      * A flag for recording whether this attribute's values are ordered.
73      * @serial
74      */

75     protected boolean ordered = false;
76
77     public Object JavaDoc clone() {
78     BasicAttribute JavaDoc attr;
79     try {
80         attr = (BasicAttribute JavaDoc)super.clone();
81     } catch (CloneNotSupportedException JavaDoc e) {
82         attr = new BasicAttribute JavaDoc(attrID, ordered);
83     }
84     attr.values = (Vector JavaDoc)values.clone();
85     return attr;
86     }
87
88     /**
89       * Determines whether obj is equal to this attribute.
90       * Two attributes are equal if their attribute-ids, syntaxes
91       * and values are equal.
92       * If the attribute values are unordered, the order that the values were added
93       * are irrelevant. If the attribute values are ordered, then the
94       * order the values must match.
95       * If obj is null or not an Attribute, false is returned.
96       *<p>
97       * By default <tt>Object.equals()</tt> is used when comparing the attribute
98       * id and its values except when a value is an array. For an array,
99       * each element of the array is checked using <tt>Object.equals()</tt>.
100       * A subclass may override this to make
101       * use of schema syntax information and matching rules,
102       * which define what it means for two attributes to be equal.
103       * How and whether a subclass makes
104       * use of the schema information is determined by the subclass.
105       * If a subclass overrides <tt>equals()</tt>, it should also override
106       * <tt>hashCode()</tt>
107       * such that two attributes that are equal have the same hash code.
108       *
109       * @param obj The possibly null object to check.
110       * @return true if obj is equal to this attribute; false otherwise.
111       * @see #hashCode
112       * @see #contains
113       */

114     public boolean equals(Object JavaDoc obj) {
115     if ((obj != null) && (obj instanceof Attribute JavaDoc)) {
116         Attribute JavaDoc target = (Attribute JavaDoc)obj;
117         
118         // Check order first
119
if (isOrdered() != target.isOrdered()) {
120         return false;
121         }
122         int len;
123         if (attrID.equals(target.getID()) &&
124             (len=size()) == target.size()) {
125         try {
126             if (isOrdered()) {
127             // Go through both list of values
128
for (int i = 0; i < len; i++) {
129                 if (!valueEquals(get(i), target.get(i))) {
130                 return false;
131                 }
132             }
133             } else {
134             // order is not relevant; check for existence
135
Enumeration JavaDoc theirs = target.getAll();
136             while (theirs.hasMoreElements()) {
137                 if (find(theirs.nextElement()) < 0)
138                 return false;
139             }
140             }
141         } catch (NamingException JavaDoc e) {
142             return false;
143         }
144         return true;
145         }
146     }
147     return false;
148     }
149
150     /**
151       * Calculates the hash code of this attribute.
152       *<p>
153       * The hash code is computed by adding the hash code of
154       * the attribute's id and that of all of its values except for
155       * values that are arrays.
156       * For an array, the hash code of each element of the array is summed.
157       * If a subclass overrides <tt>hashCode()</tt>, it should override
158       * <tt>equals()</tt>
159       * as well so that two attributes that are equal have the same hash code.
160       *
161       * @return an int representing the hash code of this attribute.
162       * @see #equals
163       */

164     public int hashCode() {
165     int hash = attrID.hashCode();
166     int num = values.size();
167     Object JavaDoc val;
168     for (int i = 0; i < num; i ++) {
169         val = values.elementAt(i);
170         if (val != null) {
171         if (val.getClass().isArray()) {
172             Object JavaDoc it;
173             int len = Array.getLength(val);
174             for (int j = 0 ; j < len ; j++) {
175             it = Array.get(val, j);
176             if (it != null) {
177                 hash += it.hashCode();
178             }
179             }
180         } else {
181             hash += val.hashCode();
182         }
183         }
184     }
185     return hash;
186     }
187
188     /**
189       * Generates the string representation of this attribute.
190       * The string consists of the attribute's id and its values.
191       * This string is meant for debugging and not meant to be
192       * interpreted programmatically.
193       * @return The non-null string representation of this attribute.
194       */

195     public String JavaDoc toString() {
196     StringBuffer JavaDoc answer = new StringBuffer JavaDoc(attrID + ": ");
197     if (values.size() == 0) {
198         answer.append("No values");
199     } else {
200         boolean start = true;
201         for (Enumeration JavaDoc e = values.elements(); e.hasMoreElements(); ) {
202         if (!start)
203             answer.append(", ");
204         answer.append(e.nextElement());
205         start = false;
206         }
207     }
208     return answer.toString();
209     }
210
211     /**
212       * Constructs a new instance of an unordered attribute with no value.
213       *
214       * @param id The attribute's id. It cannot be null.
215       */

216     public BasicAttribute(String JavaDoc id) {
217     this(id, false);
218     }
219
220     /**
221       * Constructs a new instance of an unordered attribute with a single value.
222       *
223       * @param id The attribute's id. It cannot be null.
224       * @param value The attribute's value. If null, a null
225       * value is added to the attribute.
226       */

227     public BasicAttribute(String JavaDoc id, Object JavaDoc value) {
228     this(id, value, false);
229     }
230
231     /**
232       * Constructs a new instance of a possibly ordered attribute with no value.
233       *
234       * @param id The attribute's id. It cannot be null.
235       * @param ordered true means the attribute's values will be ordered;
236       * false otherwise.
237       */

238     public BasicAttribute(String JavaDoc id, boolean ordered) {
239     attrID = id;
240     values = new Vector JavaDoc();
241     this.ordered = ordered;
242     }
243
244     /**
245       * Constructs a new instance of a possibly ordered attribute with a
246       * single value.
247       *
248       * @param id The attribute's id. It cannot be null.
249       * @param value The attribute's value. If null, a null
250       * value is added to the attribute.
251       * @param ordered true means the attribute's values will be ordered;
252       * false otherwise.
253       */

254     public BasicAttribute(String JavaDoc id, Object JavaDoc value, boolean ordered) {
255     this(id, ordered);
256     values.addElement(value);
257     }
258
259     /**
260       * Retrieves an enumeration of this attribute's values.
261       *<p>
262       * By default, the values returned are those passed to the
263       * constructor and/or manipulated using the add/replace/remove methods.
264       * A subclass may override this to retrieve the values dynamically
265       * from the directory.
266       */

267     public NamingEnumeration JavaDoc<?> getAll() throws NamingException JavaDoc {
268       return new ValuesEnumImpl();
269     }
270
271     /**
272       * Retrieves one of this attribute's values.
273       *<p>
274       * By default, the value returned is one of those passed to the
275       * constructor and/or manipulated using the add/replace/remove methods.
276       * A subclass may override this to retrieve the value dynamically
277       * from the directory.
278       */

279     public Object JavaDoc get() throws NamingException JavaDoc {
280     if (values.size() == 0) {
281         throw new
282     NoSuchElementException JavaDoc("Attribute " + getID() + " has no value");
283     } else {
284         return values.elementAt(0);
285     }
286     }
287
288     public int size() {
289       return values.size();
290     }
291
292     public String JavaDoc getID() {
293     return attrID;
294     }
295
296     /**
297       * Determines whether a value is in this attribute.
298       *<p>
299       * By default,
300       * <tt>Object.equals()</tt> is used when comparing <tt>attrVal</tt>
301       * with this attribute's values except when <tt>attrVal</tt> is an array.
302       * For an array, each element of the array is checked using
303       * <tt>Object.equals()</tt>.
304       * A subclass may use schema information to determine equality.
305       */

306     public boolean contains(Object JavaDoc attrVal) {
307     return (find(attrVal) >= 0);
308     }
309
310     // For finding first element that has a null in JDK1.1 Vector.
311
// In the Java 2 platform, can just replace this with Vector.indexOf(target);
312
private int find(Object JavaDoc target) {
313     Class JavaDoc cl;
314     if (target == null) {
315         int ct = values.size();
316         for (int i = 0 ; i < ct ; i++) {
317         if (values.elementAt(i) == null)
318             return i;
319         }
320     } else if ((cl=target.getClass()).isArray()) {
321         int ct = values.size();
322         Object JavaDoc it;
323         for (int i = 0 ; i < ct ; i++) {
324         it = values.elementAt(i);
325         if (it != null && cl == it.getClass()
326             && arrayEquals(target, it))
327             return i;
328         }
329     } else {
330         return values.indexOf(target, 0);
331     }
332     return -1; // not found
333
}
334
335     /**
336      * Determines whether two attribute values are equal.
337      * Use arrayEquals for arrays and <tt>Object.equals()</tt> otherwise.
338      */

339     private static boolean valueEquals(Object JavaDoc obj1, Object JavaDoc obj2) {
340     if (obj1 == obj2) {
341         return true; // object references are equal
342
}
343     if (obj1 == null) {
344         return false; // obj2 was not false
345
}
346     if (obj1.getClass().isArray() &&
347         obj2.getClass().isArray()) {
348         return arrayEquals(obj1, obj2);
349     }
350     return (obj1.equals(obj2));
351     }
352
353     /**
354      * Determines whether two arrays are equal by comparing each of their
355      * elements using <tt>Object.equals()</tt>.
356      */

357     private static boolean arrayEquals(Object JavaDoc a1, Object JavaDoc a2) {
358     int len;
359     if ((len = Array.getLength(a1)) != Array.getLength(a2))
360         return false;
361
362     for (int j = 0; j < len; j++) {
363         Object JavaDoc i1 = Array.get(a1, j);
364         Object JavaDoc i2 = Array.get(a2, j);
365         if (i1 == null || i2 == null) {
366         if (i1 != i2)
367             return false;
368         } else if (!i1.equals(i2)) {
369         return false;
370         }
371     }
372     return true;
373     }
374
375     /**
376       * Adds a new value to this attribute.
377       *<p>
378       * By default, <tt>Object.equals()</tt> is used when comparing <tt>attrVal</tt>
379       * with this attribute's values except when <tt>attrVal</tt> is an array.
380       * For an array, each element of the array is checked using
381       * <tt>Object.equals()</tt>.
382       * A subclass may use schema information to determine equality.
383       */

384     public boolean add(Object JavaDoc attrVal) {
385     if (isOrdered() || (find(attrVal) < 0)) {
386         values.addElement(attrVal);
387         return true;
388     } else {
389         return false;
390     }
391     }
392
393     /**
394       * Removes a specified value from 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 remove(Object JavaDoc attrval) {
403     // For the Java 2 platform, can just use "return removeElement(attrval);"
404
// Need to do the following to handle null case
405

406     int i = find(attrval);
407     if (i >= 0) {
408         values.removeElementAt(i);
409         return true;
410     }
411     return false;
412     }
413
414     public void clear() {
415     values.setSize(0);
416     }
417
418 // ---- ordering methods
419

420     public boolean isOrdered() {
421     return ordered;
422     }
423
424     public Object JavaDoc get(int ix) throws NamingException JavaDoc {
425     return values.elementAt(ix);
426     }
427
428     public Object JavaDoc remove(int ix) {
429     Object JavaDoc answer = values.elementAt(ix);
430     values.removeElementAt(ix);
431     return answer;
432     }
433
434     public void add(int ix, Object JavaDoc attrVal) {
435     if (!isOrdered() && contains(attrVal)) {
436         throw new IllegalStateException JavaDoc(
437         "Cannot add duplicate to unordered attribute");
438     }
439     values.insertElementAt(attrVal, ix);
440     }
441
442     public Object JavaDoc set(int ix, Object JavaDoc attrVal) {
443     if (!isOrdered() && contains(attrVal)) {
444         throw new IllegalStateException JavaDoc(
445         "Cannot add duplicate to unordered attribute");
446     }
447
448     Object JavaDoc answer = values.elementAt(ix);
449     values.setElementAt(attrVal, ix);
450     return answer;
451     }
452
453 // ----------------- Schema methods
454

455     /**
456       * Retrieves the syntax definition associated with this attribute.
457       *<p>
458       * This method by default throws OperationNotSupportedException. A subclass
459       * should override this method if it supports schema.
460       */

461     public DirContext JavaDoc getAttributeSyntaxDefinition() throws NamingException JavaDoc {
462         throw new OperationNotSupportedException JavaDoc("attribute syntax");
463     }
464
465     /**
466       * Retrieves this attribute's schema definition.
467       *<p>
468       * This method by default throws OperationNotSupportedException. A subclass
469       * should override this method if it supports schema.
470       */

471     public DirContext JavaDoc getAttributeDefinition() throws NamingException JavaDoc {
472     throw new OperationNotSupportedException JavaDoc("attribute definition");
473     }
474
475
476 // ---- serialization methods
477

478     /**
479      * Overridden to avoid exposing implementation details
480      * @serialData Default field (the attribute ID -- a String),
481      * followed by the number of values (an int), and the
482      * individual values.
483      */

484     private void writeObject(java.io.ObjectOutputStream JavaDoc s)
485         throws java.io.IOException JavaDoc {
486     s.defaultWriteObject(); // write out the attrID
487
s.writeInt(values.size());
488     for (int i = 0; i < values.size(); i++) {
489         s.writeObject(values.elementAt(i));
490     }
491     }
492
493     /**
494      * Overridden to avoid exposing implementation details.
495      */

496     private void readObject(java.io.ObjectInputStream JavaDoc s)
497         throws java.io.IOException JavaDoc, ClassNotFoundException JavaDoc {
498         s.defaultReadObject(); // read in the attrID
499
int n = s.readInt(); // number of values
500
values = new Vector JavaDoc(n);
501     while (--n >= 0) {
502         values.addElement(s.readObject());
503     }
504     }
505
506
507     class ValuesEnumImpl implements NamingEnumeration JavaDoc<Object JavaDoc> {
508     Enumeration JavaDoc list;
509
510     ValuesEnumImpl() {
511     list = values.elements();
512     }
513
514     public boolean hasMoreElements() {
515     return list.hasMoreElements();
516     }
517
518     public Object JavaDoc nextElement() {
519     return(list.nextElement());
520     }
521
522     public Object JavaDoc next() throws NamingException JavaDoc {
523     return list.nextElement();
524     }
525
526     public boolean hasMore() throws NamingException JavaDoc {
527     return list.hasMoreElements();
528     }
529
530     public void close() throws NamingException JavaDoc {
531     list = null;
532     }
533     }
534
535     /**
536      * Use serialVersionUID from JNDI 1.1.1 for interoperability.
537      */

538     private static final long serialVersionUID = 6743528196119291326L;
539 }
540
Popular Tags