KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > ca > commons > naming > DXAttribute


1 package com.ca.commons.naming;
2
3 import javax.naming.*;
4 import javax.naming.directory.*;
5
6 import java.util.*;
7 import java.util.logging.Logger JavaDoc;
8 import java.util.logging.Level JavaDoc;
9 import java.text.CollationKey JavaDoc;
10 import java.text.Collator JavaDoc;
11
12 import com.ca.commons.cbutil.*;
13 import com.ca.commons.jndi.SchemaOps;
14
15 /**
16  * <p>This is a schema-aware wrapper to BasicAttribute<p>
17  *
18  * <p>It goes to a lot of effort to figure out whether the attribute has
19  * string values, or contains 'byte array' values. If it contains byte array values,
20  * it also tries to figure out whether they are ASN1 values. This is important, as we
21  * need to make sure that byte array values are passed correctly to JNDI, and in addition
22  * we need to make sure that ASN1 values are passed using ';binary'.</p>
23  */

24
25 //There was Confusion here between non-string syntaxes, and 'Binary' syntaxes which in ldap means ASN.1. encoded.
26
//We have modified the class to use 'non string' (for byte arrays) and 'ASN1' (for ASN1 structures). All ASN1
27
//structures are 'non string', but attributes like jpeg photos and so on are byte arrays, but not ASN1 structures...
28

29
30 public class DXAttribute extends BasicAttribute implements Comparable JavaDoc
31 {
32     //protected boolean isNonString = false; // whether this attribute is isNonString data (e.g. ASN1 or a jpeg, an audio file etc.)
33
protected boolean isString = true; // whether this attribute is an ordinary string, or something else (e.g. ASN1 or a jpeg, an audio file etc.). Default is true (most attributes are strings).
34
protected boolean isASN1 = false;
35
36     static boolean appendBinaryOption = false; // whether to add ';binary' to the end of non String attribute names.
37

38     String JavaDoc name; // the name of the attribute (usually identical to the ID, unless ';binary' has been added to the ID)
39
String JavaDoc syntaxOID; // the OID of the Syntax (i.e. "1.3.6.1.4.1.1466.115.121.1.5" for binary)
40
String JavaDoc syntaxDesc; // the same thing as a human readable description
41
String JavaDoc description; // the free form description of the attribute that may exist in schema
42

43     private static final String JavaDoc STRING = "string";
44     private static final String JavaDoc BYTE_ARRAY = "bytes";
45     private static final String JavaDoc ASN1 = "asn1";
46     static Hashtable knownAttributeTypes; // a list of known 'attributes, matched against the constants above
47

48     static SchemaOps schema; // the schema of the most recently connected to directory
49

50
51     private CollationKey JavaDoc collationKey; // used for language-sensitive sorting.
52
private static Collator JavaDoc myCollator = Collator.getInstance(); // used for language-sensitive sorting.
53

54     private final static Logger JavaDoc log = Logger.getLogger(DXAttribute.class.getName()); // ...It's round it's heavy it's wood... It's better than bad, it's good...
55

56     static
57     {
58         knownAttributeTypes = new Hashtable(100);
59     }
60
61     /**
62      * Normal constructor for an Attribute with no (current) value.
63      * @param ID the name of the attribute (e.g. "userCertificate")
64      */

65
66     public DXAttribute(String JavaDoc ID)
67     {
68         super(ID);
69         init();
70     }
71
72     /**
73      * Normal constructor an Attribute with a single value.
74      * @param ID the name of the attribute (e.g. "commonName")
75      * @param value the value of the attribute (String or byte array). e.g. "Fred"
76      */

77
78     public DXAttribute(String JavaDoc ID, Object JavaDoc value)
79     {
80         super(ID, value);
81         init();
82     }
83
84     /**
85      * Make a copy of a normal, pre-existing attribute.
86      * @param att the attribute (e.g. BasicAttribute) to wrap.
87      */

88
89     public DXAttribute(Attribute att)
90     {
91         super(att.getID());
92         try
93         {
94             addValues(att.getAll());
95         }
96         catch (NamingException e)
97         {
98             log.log(Level.WARNING, "error reading attribute values for attribute " + getID() + "\n", e);
99         }
100
101         setName(att.getID()); // ?? necessary??
102

103         init();
104     }
105
106     /**
107      * Creates an attribute with an enumeration of existing values.
108      * @param ID the name of the attribute (e.g. "favoriteDrink")
109      * @param values a set of values (e.g. "midori"... "cointreau"... "lemon juice"... "japanese slipper"
110      */

111
112     public DXAttribute(String JavaDoc ID, NamingEnumeration values)
113     {
114         super(ID);
115         addValues(values);
116         init();
117     }
118
119     /**
120      * Adds a series of values to the attribute.
121      * @param values a bunch of new values to append to the attribute
122      */

123     public void addValues(NamingEnumeration values)
124     {
125         try
126         {
127             while (values.hasMore())
128             {
129                 add(values.next());
130             }
131         }
132         catch (NamingException e)
133         {
134             log.log(Level.WARNING, "error adding values for attribute " + getID(), e);
135         }
136     }
137
138     /**
139      * Attempts to sort the values of the attribute alphabetically. This is a
140      * relatively expensive operation, and should be used sparingly. (e.g. at GUI
141      * display time)
142      */

143     public void sort()
144     {
145         if (values.size()<2)
146             return; // nothing to do.
147

148         try
149         {
150             // $%^# don't know how to write this to keep both java 1.4 & 1.5 happy - compiles under both, but 1.5 IDEs may flag this...
151
Collections.sort((List)values);
152         }
153         catch (ClassCastException JavaDoc e)
154         {
155             // nope, can't do that...
156
}
157         catch (UnsupportedOperationException JavaDoc e)
158         {
159             // nope, can't do that either...
160
}
161     }
162
163     /**
164      * This sets the standard schema to use while this connection is open.
165      * (It may be possible in future releases to set schema on a per-Attribute
166      * basis - it is not clear yet whether this would be useful.)
167      */

168     public static void setDefaultSchema(SchemaOps defaultSchema)
169     {
170         schema = defaultSchema;
171     }
172
173     /**
174      * <p>Code common to all constructors, run at the *end* of each constructor.</p>
175      */

176     protected void init()
177     {
178         // figure out whether this is a byte array, and whether it is an ASN1 structure
179
setAttributeType();
180
181         // used for sorting. XXX should this be delayed until we actually need to do any sorting??
182
collationKey = myCollator.getCollationKey(getID());
183     }
184
185     /**
186      * This method examines the schema to test whether the attribute is string, byte array or ASN1 data.
187      */

188
189     protected void setAttributeType()
190     {
191         // quickly handle schema atts.
192
String JavaDoc ID = getID();
193
194         // skip 'synthetic' schemas
195
if ("SYNTAXNAMENUMERICOIDDESCEQUALITY".indexOf(ID) != -1) return;
196
197         ID = ID.toLowerCase();
198
199         // see if we've already cached details about this attribute ID
200
if (knownAttributeTypes.get(ID) != null)
201         {
202             isString = STRING.equals(knownAttributeTypes.get(ID));
203             isASN1 = ASN1.equals(knownAttributeTypes.get(ID));
204         }
205         // if the attribute ends with ;binary, then it must be both isNonString and ASN1
206
else if (ID.endsWith(";binary"))
207         {
208             isString = false;
209             isASN1 = true;
210         }
211         else if (schema != null)
212         {
213             setAttributeTypeFromSchema(); // sets isString and isASN1 variables
214
}
215         else // guessing time - we don't have a schema, but we'll try to figure it out from the value.
216
{
217             try
218             {
219                 if (size() > 0)
220                 {
221                     Object JavaDoc value = get();
222
223                     isString = (value == null || value instanceof String JavaDoc);
224
225                     if (!isString)
226                         isASN1 = isKnownASN1Attribute(ID); // more guessing...
227
}
228             }
229             catch (NamingException e)
230             {
231                 log.log(Level.WARNING, "Unexpected error reading value from attribute " + ID, e);
232             }
233         }
234
235         updateTypesHashtable(ID);
236     }
237
238     private void updateTypesHashtable(String JavaDoc ID)
239     {
240         if (knownAttributeTypes.contains(ID) == false)
241         {
242             if (isString)
243                 knownAttributeTypes.put(ID, STRING);
244             else if (isASN1)
245                 knownAttributeTypes.put(ID, ASN1);
246             else
247                 knownAttributeTypes.put(ID, BYTE_ARRAY);
248         }
249     }
250
251     /**
252      * Does this attribute have a valid value (i.e. not null, or empty string).
253      */

254
255     public static boolean isEmpty(Attribute att)
256     {
257         if (att == null || att.size() == 0)
258         {
259             return true;
260         }
261         else if (att.size() == 1)
262         {
263             Object JavaDoc val = null;
264             try
265             {
266                 val = att.get();
267             }
268             catch (NamingException e)
269             {
270                 return true; // assume naming exception means empty attribute... (?)
271
}
272
273             if (val == null || "".equals(val))
274                 return true;
275         }
276
277         return false;
278     }
279     /**
280      * This returns whether the Syntax is a non string syntax that should be passed
281      * via a byte array in JNDI
282      *
283      * @param syntaxName
284      * @return
285      */

286     public static boolean isStringSyntax(String JavaDoc syntaxName)
287     {
288         if (syntaxName == null)
289             return true; //don't know - default to 'yes'
290

291         int pos = syntaxName.indexOf("1.3.6.1.4.1.1466.115.121.1.");
292         if (pos == -1)
293             return true; //don't know - default to 'yes'
294

295         // some faffing around to get the final number of the OID. Could probably be neatened up :-).
296
String JavaDoc number = syntaxName.substring(pos + "1.3.6.1.4.1.1466.115.121.1.".length());
297
298         if (number.length() > 2)
299         {
300             number = number.substring(0, 2);
301             char c = number.charAt(1);
302             if (Character.isDigit(c) == false)
303                 number = number.substring(0, 1);
304         }
305
306         try
307         {
308             int finalNumber = Integer.parseInt(number);
309
310             switch (finalNumber)
311             {
312                 case 4:
313                     return false; // 1.3.6.1.4.1.1466.115.121.1.4 - audio
314
case 5:
315                     return false; // 1.3.6.1.4.1.1466.115.121.1.5 - ASN1 binary
316
case 8:
317                     return false; // 1.3.6.1.4.1.1466.115.121.1.8 - certificate
318
case 9:
319                     return false; // 1.3.6.1.4.1.1466.115.121.1.9 - certificate list
320
case 10:
321                     return false; // 1.3.6.1.4.1.1466.115.121.1.10 - certificate pair
322
case 28:
323                     return false; // 1.3.6.1.4.1.1466.115.121.1.28 - jpeg
324
case 40:
325                     return false; // 1.3.6.1.4.1.1466.115.121.1.40 - octet string
326
default:
327                     return true;
328             }
329         }
330         catch (NumberFormatException JavaDoc e)
331         {
332             log.log(Level.WARNING, "Unexpected error parsing syntax: " + syntaxName, e);
333             return true;
334         }
335
336     }
337
338     /**
339      * Returns whether the attribute is an ASN.1 structure
340      * (and thus a candidate for having ;binary tacked on to its name)
341      *
342      * @param syntaxName the name of the syntax (usually a thumping great OID)
343      * @return
344      */

345     public static boolean isASN1Syntax(String JavaDoc syntaxName)
346     {
347         if (syntaxName == null)
348             return false;
349
350         int pos = syntaxName.indexOf("1.3.6.1.4.1.1466.115.121.1.");
351         if (pos == -1)
352             return false;
353
354         String JavaDoc number = syntaxName.substring(pos + "1.3.6.1.4.1.1466.115.121.1.".length());
355
356         if (number.length() > 2)
357         {
358             number = number.substring(0, 2);
359             char c = number.charAt(1);
360             if (Character.isDigit(c) == false)
361                 number = number.substring(0, 1);
362         }
363
364         try
365         {
366             int finalNumber = Integer.parseInt(number);
367
368             switch (finalNumber)
369             {
370                 case 5:
371                     return true; // 1.3.6.1.4.1.1466.115.121.1.5 - ASN1 binary
372
case 8:
373                     return true; // 1.3.6.1.4.1.1466.115.121.1.8 - certificate
374
case 9:
375                     return true; // 1.3.6.1.4.1.1466.115.121.1.9 - certificate list
376
case 10:
377                     return true; // 1.3.6.1.4.1.1466.115.121.1.10 - certificate pair
378
default:
379                     return false;
380             }
381         }
382         catch (NumberFormatException JavaDoc e)
383         {
384             log.log(Level.WARNING, "Unexpected error parsing syntax: " + syntaxName, e);
385             return false;
386         }
387
388     }
389
390     /**
391      * <p>Look up the attribute ID in the schema, and see whether the
392      * syntax found there is a String, or if it is a byte array whether it is also an ASN1 structure.</p>
393      * <p>This method sets the following globals:</p>
394      * syntaxOID<br>
395      * isString<br>
396      * isASN1<br>
397      */

398     public void setAttributeTypeFromSchema()
399     {
400         if (schema != null)
401         {
402             try
403             {
404                 String JavaDoc attributeNameInSchema = "AttributeDefinition/" + getID();
405                 Attributes atts = schema.getAttributes(attributeNameInSchema);
406
407                 Attribute syntaxAttribute = null;
408                 while (atts!=null && (syntaxAttribute = atts.get("SUP")) != null)
409                 {
410                     atts = schema.getAttributes("AttributeDefinition/" + syntaxAttribute.get().toString());
411                 }
412                 if (atts!=null)
413                      syntaxAttribute = atts.get("SYNTAX");
414
415                 if (syntaxAttribute != null)
416                 {
417                     syntaxOID = syntaxAttribute.toString();
418                     isString = isStringSyntax(syntaxOID);
419                     if (!isString)
420                         isASN1 = isASN1Syntax(syntaxOID);
421                 }
422                 else
423                 {
424                     log.info(" Can't find SYNTAX for... " + getID());
425                 }
426             }
427             // XXX does this actually work on any known ldap server??
428
// XXX - if so, should modify above so that when atts == null the below is run I guess...
429
catch (NamingException e) // usually means the attribute wasn't found under that name. Try again using ';binary' suffix.
430
{
431                 try
432                 {
433                     Attributes atts = schema.getAttributes("AttributeDefinition/" + getID() + ";binary");
434
435                     // if we find anything at all, it must be an ASN1 ;binary attribute...
436
if (atts != null)
437                     {
438                         isString = false;
439                         isASN1 = true;
440                     }
441                 }
442                 catch (Exception JavaDoc e2) // give up
443
{
444                     log.log(Level.INFO, "can't find syntax for attribute " + getID(), e);
445                 }
446             }
447         }
448         else
449         {
450             log.fine("no schema available");
451         }
452     }
453
454     /**
455      * Whether the attribute contains isNonString data; ideally found by checking Syntax, but
456      * often set by inspection of the attribute value (whether it is a Byte array).
457      *
458      * @deprecated use isString instead
459      */

460     public boolean isBinary()
461     {
462         return !isString();
463     }
464
465
466     /**
467      * Whether the attribute contains isNonString data; ideally found by checking Syntax, but
468      * often set by inspection of the attribute value (whether it is a Byte array).
469      */

470     public boolean isString()
471     {
472         return isString;
473     }
474
475     /**
476      * Sets the isNonString status of the attribute. Shouldn't be required any more;
477      * should be set by syntax checking.
478      *
479      * @deprecated use setString() instead
480      */

481     public void setBinary(boolean bin)
482     {
483         setString(!bin);
484     }
485
486     /**
487      * Sets the isNonString status of the attribute. Shouldn't be required any more;
488      * should be set by syntax checking.
489      */

490     public void setString(boolean stringStatus)
491     {
492         knownAttributeTypes.put(getID(), (stringStatus)?STRING:BYTE_ARRAY);
493         isString = stringStatus;
494     }
495
496     /**
497      * Utility Function: takes a schema Entry class such as 'AttributeDefinition/cn', *
498      * and returns the result of looking up a particular attribute within that
499      * (e.g. 'DESC').
500      *
501      * @param schemaEntry the full schema entry name to lookup, e.g. 'ClassDefinition/alias'
502      * @param schemaAttribute the attribute to look up, e.g. 'MUST'
503      * @return the value of the schema entry attribute (e.g. '2.5.4.1')
504      */

505
506     public String JavaDoc schemaLookup(String JavaDoc schemaEntry, String JavaDoc schemaAttribute)
507     {
508         if (schema == null)
509             return null;
510         else
511             return schema.schemaLookup(schemaEntry, schemaAttribute);
512     }
513
514     /**
515      * returns whether this attribute has a description in the schema
516      * @return
517      */

518     public boolean hasOptions()
519     {
520         if (description == null) // try to load a description if it exists
521
getDescription();
522
523         if (description == null || description == "" || description.indexOf("LIST:") < 0)
524             return false;
525
526         return true;
527     }
528
529     /**
530      * IF a description field has been set in the schema, and IF that
531      * description field LISTs a set of values, read 'em and return them
532      * as a string array.
533      */

534
535     public String JavaDoc[] getOptions()
536     {
537         if (description == null)
538             getDescription();
539         if (description == null || description == "")
540             return new String JavaDoc[0];
541
542         // can't be fagged working out java generic parse stuff - do own quickie...
543
int len = description.length();
544         int pos = description.indexOf("LIST:");
545         if (pos < 0) return new String JavaDoc[0];
546         pos += 5;
547         int next = pos;
548
549         Vector resVect = new Vector();
550         resVect.add("");
551 // String option;
552
while (pos < len && pos > 0)
553         {
554             next = description.indexOf(',', next + 1);
555             if (next < 0)
556             {
557                 resVect.add(description.substring(pos));
558                 pos = 0;
559             }
560             else if (description.charAt(next - 1) != '\\')
561             {
562                 resVect.add(description.substring(pos, next));
563                 pos = next + 1;
564             }
565             else
566             {
567                 next++; // move past the escaped comma
568
}
569         }
570
571         // dump vector into string array, unescaping as we go.
572
String JavaDoc[] result = new String JavaDoc[resVect.size()];
573         for (int i = 0; i < resVect.size(); i++)
574             result[i] = unEscape((String JavaDoc) resVect.elementAt(i));
575
576         return result;
577     }
578
579     public String JavaDoc unEscape(String JavaDoc escapeMe)
580     {
581         int slashpos = escapeMe.indexOf('\\');
582         while (slashpos >= 0)
583         {
584             escapeMe = escapeMe.substring(0, slashpos) + escapeMe.substring(slashpos + 1);
585             slashpos = escapeMe.indexOf('\\');
586         }
587         return escapeMe;
588     }
589
590     /**
591      * returns the OID of the schema entry corresponding to this particular entry. Whoo hoo... something like
592      * '1.3.6.1.4.1.1466.115.121.1.27'.
593      * @return
594      */

595
596     public String JavaDoc getSyntaxOID()
597     {
598         if (syntaxOID == null)
599             setAttributeTypeFromSchema(); // sets syntaxOID
600

601         if (syntaxOID == null)
602             return "<unknown>";
603         else
604             return syntaxOID;
605     }
606
607
608     /**
609      * Returns (and caches) the syntax description.
610      */

611     public String JavaDoc getSyntaxDesc()
612     {
613         if (syntaxDesc == null)
614             syntaxDesc = schemaLookup("SyntaxDefinition/" + getSyntaxOID(), "DESC");
615         return syntaxDesc;
616     }
617
618
619     public String JavaDoc getSyntaxName()
620     {
621         if (syntaxOID == null)
622             setAttributeTypeFromSchema(); // sets syntaxOID
623

624         if (syntaxOID == null)
625             return "<unknown>";
626         else
627             return schema.translateOID(syntaxOID);
628     }
629
630
631     /**
632      * Usefull escape to allow renaming of attributes. Use with caution,
633      * since an arbitrary name may not correspond to a valid schema name.
634      */

635     public void setName(String JavaDoc newName)
636     {
637         name = newName;
638     }
639
640     public String JavaDoc getName()
641     {
642         if (name == null)
643             name = schemaLookup("AttributeDefinition/" + getID(), "NAME");
644         if (name == null)
645             name = getID();
646
647         return name;
648     }
649
650     /**
651      * Returns the attribute's 'DESC' field from the attribute schema
652      * definition, if such exists (it's an extension). Not to be
653      * confused with the Syntax Description, which is something like "isNonString".
654      */

655
656     public String JavaDoc getDescription()
657     {
658         if (description == null)
659         {
660             description = schemaLookup("AttributeDefinition/" + getID(), "DESC");
661             if (description == null) // if description is still null, set it
662
description = ""; // to an empty string, to avoid repeatedly looking it up.
663
}
664         return description;
665     }
666
667     /**
668      * <p>A synonym for getID(). Use 'toDebugString()' for the complete printout.</p>
669      *
670      * @return
671      */

672     public String JavaDoc toString()
673     {
674         return getID();
675     }
676
677     /**
678      * General descriptive string: used mainly for debugging...
679      */

680
681     public String JavaDoc toDebugString()
682     {
683         int count = 1;
684         try
685         {
686             StringBuffer JavaDoc result = new StringBuffer JavaDoc().append("att: ").append(getID()).append(" (size=").append(size()).append(") ");
687
688             NamingEnumeration vals = getAll();
689             if (!isString)
690             {
691                 result.append(" (Byte Array) ");
692                 while (vals.hasMore())
693                 {
694                     try
695                     {
696                         byte[] b = (byte[]) vals.next();
697                         result.append("\n ").append((count++)).append(":").append(((b == null) ? "null" : CBBase64.binaryToString(b)));
698                     }
699                     catch (ClassCastException JavaDoc cce)
700                     {
701                         result.append("\n ").append((count++)).append(": <error - not a byte array>");
702                     }
703                 }
704             }
705             else
706             {
707                 while (vals.hasMore())
708                 {
709                     Object JavaDoc o = vals.next();
710                     result.append("\n ").append((count++)).append(":").append(((o == null) ? "null" : o.toString()));
711                 }
712             }
713
714             return result.append("\n").toString();
715         }
716         catch (NamingException e)
717         {
718             log.log(Level.WARNING, "error listing values for " + getID(), e);
719             return (getID() + " (error listing values)");
720         }
721
722
723     }
724
725     // ugly, ugly hack to add ';binary' when writting data to dir, but
726
// not otherwise.
727
public static void setVerboseBinary(boolean status)
728     {
729         appendBinaryOption = status;
730         log.fine("setting isNonString attribute status to " + status);
731     }
732
733     /**
734      * This returns the name of the attribute.
735      * @return the attribute name; e.g. 'commonName'
736      */

737
738     //TODO: should this use the OID instead? Would solve problems with loonies who
739
//TODO: use different names for the same attribute in different place
740

741     public String JavaDoc getID()
742     {
743         String JavaDoc id = super.getID();
744         if (appendBinaryOption && !(id.endsWith(";binary")))
745         {
746             //System.out.println("binaryness = " + isNonString);
747
// TODO: this should only happen for ASN.1. syntaxes.
748
if (isASN1)
749             {
750                 id = id + ";binary";
751                 log.info("appending ;binary to attribute name "+id);
752             }
753
754         }
755         return id;
756     }
757
758     /**
759      * A last resort hack to guess whether an otherwise unknown attribute is
760      * an ASN1 structure. This should only be used if the schema is unavailable.
761      * @param id
762      * @return
763      */

764
765     public boolean isKnownASN1Attribute(String JavaDoc id)
766     {
767         String JavaDoc search = id.toLowerCase();
768         if (search.indexOf("certificate") >= 0)
769             return true;
770         else if (search.indexOf("revocation") >= 0)
771             return true;
772         else if (search.indexOf("supportedalgorithms") >= 0)
773             return true;
774         else if (search.indexOf("userpkcs12") >= 0)
775             return true;
776
777         return false;
778     }
779
780
781     /**
782      * This method gets all the values of an attribute. Useful only
783      * for multivalued attributes (use get() otherwise).
784      *
785      * @return all the values of this attribute in a String Array.
786      * XXX - assumes all values are strings??
787      */

788
789     public Object JavaDoc[] getValues()
790     {
791         Object JavaDoc[] values = new String JavaDoc[size()];
792
793         try
794         {
795             for (int i = 0; i < size(); i++)
796                 values[i] = get(i);
797             return values;
798         }
799         catch (NamingException e)
800         {
801             return new String JavaDoc[]{};
802         }
803     }
804
805
806     /**
807      * Gets rid of null values and empty strings from the value set.
808      */

809     public void trim()
810     {
811         for (int i = size() - 1; i > 0; i--)
812         {
813             Object JavaDoc o = null;
814             try
815             {
816                 o = get(i);
817                 if (o == null || "".equals(o))
818                 {
819                     remove(i);
820                 }
821             }
822             catch (NamingException e) // shouldn't happen...
823
{
824                 log.log(Level.WARNING, "Bad Attribute value in DXAttribute - removing ", e);
825                 remove(i); // .. but remove offending entry if it does.
826

827             }
828         }
829     }
830
831     public void setOrdered(boolean state)
832     {
833         ordered = state;
834     }
835
836
837     /**
838      * Returns true if this attribute is a SINGLE-VALUE attribute.
839      *
840      * @return true if this attribute is a SINGLE-VALUE attribute,
841      * false otherwise.
842      */

843
844     public boolean isSingleValued()
845     {/* TE */
846         return schema.isAttributeSingleValued(getName());
847     }
848
849     /**
850      * <p>The collation key is usually set by the constructor
851      * based on getID(), but
852      * may be over-ridden here if required. Not sure that this
853      * will ever be necessary; maybe if doing something insanely
854      * clever across multiple platforms with different languages?</p>
855      *
856      * @param key
857      */

858     public void setCollationKey(CollationKey JavaDoc key)
859     {
860         collationKey = key;
861     }
862
863     /**
864      * <p>This returns the collation key used for language sensitive
865      * sorting.</p>
866      *
867      * @return
868      */

869     public CollationKey JavaDoc getCollationKey()
870     {
871         return collationKey;
872     }
873
874     /**
875      * <p>This is intended to compare two DXAttribute objects, and will
876      * throw a class cast exception for anything else. It sorts on
877      * their internal collationkeys.</p>
878      *
879      * @param o
880      * @return
881      */

882     public int compareTo(Object JavaDoc o)
883     {
884         return collationKey.compareTo(((DXAttribute) o).getCollationKey());
885     }
886 }
Popular Tags