001/*
002 *  Licensed to the Apache Software Foundation (ASF) under one
003 *  or more contributor license agreements.  See the NOTICE file
004 *  distributed with this work for additional information
005 *  regarding copyright ownership.  The ASF licenses this file
006 *  to you under the Apache License, Version 2.0 (the
007 *  "License"); you may not use this file except in compliance
008 *  with the License.  You may obtain a copy of the License at
009 *
010 *    http://www.apache.org/licenses/LICENSE-2.0
011 *
012 *  Unless required by applicable law or agreed to in writing,
013 *  software distributed under the License is distributed on an
014 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 *  KIND, either express or implied.  See the License for the
016 *  specific language governing permissions and limitations
017 *  under the License.
018 *
019 */
020package org.apache.directory.api.ldap.model.schema;
021
022
023
024
025/**
026 * An attributeType specification. attributeType specifications describe the
027 * nature of attributes within the directory. The attributeType specification's
028 * properties are accessible through this interface.
029 * <p>
030 * According to ldapbis [MODELS]:
031 * </p>
032 *
033 * <pre>
034 *  4.1.2. Attribute Types
035 *
036 *    Attribute Type definitions are written according to the ABNF:
037 *
038 *      AttributeTypeDescription = LPAREN WSP
039 *          numericoid                   ; object identifier
040 *          [ SP &quot;NAME&quot; SP qdescrs ]     ; short names (descriptors)
041 *          [ SP &quot;DESC&quot; SP qdstring ]    ; description
042 *          [ SP &quot;OBSOLETE&quot; ]            ; not active
043 *          [ SP &quot;SUP&quot; SP oid ]          ; supertype
044 *          [ SP &quot;EQUALITY&quot; SP oid ]     ; equality matching rule
045 *          [ SP &quot;ORDERING&quot; SP oid ]     ; ordering matching rule
046 *          [ SP &quot;SUBSTR&quot; SP oid ]       ; substrings matching rule
047 *          [ SP &quot;SYNTAX&quot; SP noidlen ]   ; value syntax
048 *          [ SP &quot;SINGLE-VALUE&quot; ]        ; single-value
049 *          [ SP &quot;COLLECTIVE&quot; ]          ; collective
050 *          [ SP &quot;NO-USER-MODIFICATION&quot; ]; not user modifiable
051 *          [ SP &quot;USAGE&quot; SP usage ]      ; usage
052 *          extensions WSP RPAREN        ; extensions
053 *
054 *      usage = &quot;userApplications&quot;     / ; user
055 *              &quot;directoryOperation&quot;   / ; directory operational
056 *              &quot;distributedOperation&quot; / ; DSA-shared operational
057 *              &quot;dSAOperation&quot;           ; DSA-specific operational
058 *
059 *    where:
060 *      [numericoid] is object identifier assigned to this attribute type;
061 *      NAME [qdescrs] are short names (descriptors) identifying this
062 *          attribute type;
063 *      DESC [qdstring] is a short descriptive string;
064 *      OBSOLETE indicates this attribute type is not active;
065 *      SUP oid specifies the direct supertype of this type;
066 *      EQUALITY, ORDERING, SUBSTRING provide the oid of the equality,
067 *          ordering, and substrings matching rules, respectively;
068 *      SYNTAX identifies value syntax by object identifier and may suggest
069 *          a minimum upper bound;
070 *      COLLECTIVE indicates this attribute type is collective [X.501];
071 *      NO-USER-MODIFICATION indicates this attribute type is not user
072 *          modifiable;
073 *      USAGE indicates the application of this attribute type; and
074 *      [extensions] describe extensions.
075 *
076 *    Each attribute type description must contain at least one of the SUP
077 *    or SYNTAX fields.
078 *
079 *    Usage of userApplications, the default, indicates that attributes of
080 *    this type represent user information.  That is, they are user
081 *    attributes.
082 *
083 *    COLLECTIVE requires usage userApplications.  Use of collective
084 *    attribute types in LDAP is not discussed in this technical
085 *    specification.
086 *
087 *    A usage of directoryOperation, distributedOperation, or dSAOperation
088 *    indicates that attributes of this type represent operational and/or
089 *    administrative information.  That is, they are operational attributes.
090 *
091 *    directoryOperation usage indicates that the attribute of this type is
092 *    a directory operational attribute.  distributedOperation usage
093 *    indicates that the attribute of this DSA-shared usage operational
094 *    attribute.  dSAOperation usage indicates that the attribute of this
095 *    type is a DSA-specific operational attribute.
096 *
097 *    NO-USER-MODIFICATION requires an operational usage.
098 *
099 *    Note that the [AttributeTypeDescription] does not list the matching
100 *    rules which can be used with that attribute type in an extensibleMatch
101 *    search filter.  This is done using the 'matchingRuleUse' attribute
102 *    described in Section 4.1.4.
103 *
104 *    This document refines the schema description of X.501 by requiring
105 *    that the SYNTAX field in an [AttributeTypeDescription] be a string
106 *    representation of an object identifier for the LDAP string syntax
107 *    definition with an optional indication of the suggested minimum bound
108 *    of a value of this attribute.
109 *
110 *    A suggested minimum upper bound on the number of characters in a value
111 *    with a string-based syntax, or the number of bytes in a value for all
112 *    other syntaxes, may be indicated by appending this bound count inside
113 *    of curly braces following the syntax's OBJECT IDENTIFIER in an
114 *
115 *    Attribute Type Description.  This bound is not part of the syntax name
116 *    itself.  For instance, &quot;1.3.6.4.1.1466.0{64}&quot; suggests that server
117 *    implementations should allow a string to be 64 characters long,
118 *    although they may allow longer strings.  Note that a single character
119 *    of the Directory String syntax may be encoded in more than one octet
120 *    since UTF-8 is a variable-length encoding.
121 * </pre>
122 *
123 * @see <a href="http://www.faqs.org/rfcs/rfc2252.html">RFC 2252 Section 4.2</a>
124 * @see <a
125 *      href="http://www.ietf.org/internet-drafts/draft-ietf-ldapbis-models-11.txt">
126 *      ldapbis [MODELS]</a>
127 * @see DescriptionUtils#getDescription(AttributeType)
128 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
129 */
130public class AttributeType extends AbstractSchemaObject implements Cloneable
131{
132    /** The mandatory serialVersionUID */
133    public static final long serialVersionUID = 1L;
134
135    /** The syntax OID associated with this AttributeType */
136    protected String syntaxOid;
137
138    /** The syntax associated with the syntaxID */
139    protected LdapSyntax syntax;
140
141    /** The equality OID associated with this AttributeType */
142    protected String equalityOid;
143
144    /** The equality MatchingRule associated with the equalityID */
145    protected MatchingRule equality;
146
147    /** The substring OID associated with this AttributeType */
148    protected String substringOid;
149
150    /** The substring MatchingRule associated with the substringID */
151    protected MatchingRule substring;
152
153    /** The ordering OID associated with this AttributeType */
154    protected String orderingOid;
155
156    /** The ordering MatchingRule associated with the orderingID */
157    protected MatchingRule ordering;
158
159    /** The superior AttributeType OID */
160    protected String superiorOid;
161
162    /** The superior AttributeType */
163    protected AttributeType superior;
164
165    /** whether or not this type is single valued */
166    protected boolean isSingleValued = false;
167
168    /** whether or not this type is a collective attribute */
169    protected boolean isCollective = false;
170
171    /** whether or not this type can be modified by directory users */
172    protected boolean canUserModify = true;
173
174    /** the usage for this attributeType */
175    protected UsageEnum usage = UsageEnum.USER_APPLICATIONS;
176
177    /** the length of this attribute in bytes */
178    protected long syntaxLength = 0L;
179
180
181    /**
182     * Creates a AttributeType object using a unique OID.
183     *
184     * @param oid the OID for this AttributeType
185     */
186    public AttributeType( String oid )
187    {
188        super( SchemaObjectType.ATTRIBUTE_TYPE, oid );
189    }
190
191
192    /**
193     * Gets whether or not this AttributeType is single-valued.
194     *
195     * @return true if only one value can exist for this AttributeType, false
196     *         otherwise
197     */
198    public boolean isSingleValued()
199    {
200        return isSingleValued;
201    }
202
203
204    /**
205     * Gets whether or not this AttributeType can be modified by a user.
206     *
207     * @return true if users can modify it, false if only the directory can.
208     */
209    public boolean isUserModifiable()
210    {
211        return canUserModify;
212    }
213
214
215    /**
216     * Gets whether or not this AttributeType is a collective attribute.
217     *
218     * @return true if the attribute is collective, false otherwise
219     */
220    public boolean isCollective()
221    {
222        return isCollective;
223    }
224
225
226    /**
227     * Determines the usage for this AttributeType.
228     *
229     * @return a type safe UsageEnum
230     */
231    public UsageEnum getUsage()
232    {
233        return usage;
234    }
235
236
237    /**
238     * Gets a length limit for this AttributeType.
239     *
240     * @return the length of the attribute
241     */
242    public long getSyntaxLength()
243    {
244        return syntaxLength;
245    }
246
247
248    /**
249     * Gets the the superior AttributeType of this AttributeType.
250     *
251     * @return the superior AttributeType for this AttributeType
252     */
253    public AttributeType getSuperior()
254    {
255        return superior;
256    }
257
258
259    /**
260     * Gets the OID of the superior AttributeType for this AttributeType.
261     *
262     * @return The OID of the superior AttributeType for this AttributeType.
263     */
264    public String getSuperiorOid()
265    {
266        return superiorOid;
267    }
268
269
270    /**
271     * Gets the Name of the superior AttributeType for this AttributeType.
272     *
273     * @return The Name of the superior AttributeType for this AttributeType.
274     */
275    public String getSuperiorName()
276    {
277        if ( superior != null )
278        {
279            return superior.getName();
280        }
281        else
282        {
283            return superiorOid;
284        }
285    }
286
287
288    /**
289     * Gets the Syntax for this AttributeType's values.
290     *
291     * @return the value syntax
292     */
293    public LdapSyntax getSyntax()
294    {
295        return syntax;
296    }
297
298
299    /**
300     * Gets the Syntax name for this AttributeType's values.
301     *
302     * @return the value syntax name
303     */
304    public String getSyntaxName()
305    {
306        if ( syntax != null )
307        {
308            return syntax.getName();
309        }
310        else
311        {
312            return syntaxOid;
313        }
314    }
315
316
317    /**
318     * Gets the Syntax OID for this AttributeType's values.
319     *
320     * @return the value syntax's OID
321     */
322    public String getSyntaxOid()
323    {
324        return syntaxOid;
325    }
326
327
328    /**
329     * Gets the MatchingRule for this AttributeType used for equality matching.
330     *
331     * @return the equality matching rule
332     */
333    public MatchingRule getEquality()
334    {
335        return equality;
336    }
337
338
339    /**
340     * Gets the Equality OID for this AttributeType's values.
341     *
342     * @return the value Equality's OID
343     */
344    public String getEqualityOid()
345    {
346        return equalityOid;
347    }
348
349
350    /**
351     * Gets the Equality Name for this AttributeType's values.
352     *
353     * @return the value Equality's Name
354     */
355    public String getEqualityName()
356    {
357        if ( equality != null )
358        {
359            return equality.getName();
360        }
361        else
362        {
363            return equalityOid;
364        }
365    }
366
367
368    /**
369     * Gets the MatchingRule for this AttributeType used for Ordering matching.
370     *
371     * @return the Ordering matching rule
372     */
373    public MatchingRule getOrdering()
374    {
375        return ordering;
376    }
377
378
379    /**
380     * Gets the MatchingRule name for this AttributeType used for Ordering matching.
381     *
382     * @return the Ordering matching rule name
383     */
384    public String getOrderingName()
385    {
386        if ( ordering != null )
387        {
388            return ordering.getName();
389        }
390        else
391        {
392            return orderingOid;
393        }
394    }
395
396
397    /**
398     * Gets the Ordering OID for this AttributeType's values.
399     *
400     * @return the value Equality's OID
401     */
402    public String getOrderingOid()
403    {
404        return orderingOid;
405    }
406
407
408    /**
409     * Gets the MatchingRule for this AttributeType used for Substr matching.
410     *
411     * @return the Substr matching rule
412     */
413    public MatchingRule getSubstring()
414    {
415        return substring;
416    }
417
418
419    /**
420     * Gets the MatchingRule name for this AttributeType used for Substring matching.
421     *
422     * @return the Substring matching rule name
423     */
424    public String getSubstringName()
425    {
426        if ( substring != null )
427        {
428            return substring.getName();
429        }
430        else
431        {
432            return substringOid;
433        }
434    }
435
436
437    /**
438     * Gets the Substr OID for this AttributeType's values.
439     *
440     * @return the value Substr's OID
441     */
442    public String getSubstringOid()
443    {
444        return substringOid;
445    }
446
447
448    /**
449     * Tells if the attributeType is a USER attribute or not
450     * @return true if this is a USER attributeType
451     */
452    public boolean isUser()
453    {
454        return usage == UsageEnum.USER_APPLICATIONS;
455    }
456
457
458    /**
459     * Tells if the attributeType is an OPERATIONAL attribute or not
460     * @return true if this is an OPERATIONAL attributeType
461     */
462    public boolean isOperational()
463    {
464        return usage != UsageEnum.USER_APPLICATIONS;
465    }
466
467
468    /**
469     * Checks to see if this AttributeType is the ancestor of another
470     * attributeType.
471     *
472     * @param descendant the perspective descendant to check
473     * @return true if the descendant is truly a derived from this AttributeType
474     */
475    public boolean isAncestorOf( AttributeType descendant )
476    {
477        if ( ( descendant == null ) || this.equals( descendant ) )
478        {
479            return false;
480        }
481
482        return isAncestorOrEqual( this, descendant );
483    }
484
485
486    /**
487     * Checks to see if this AttributeType is the descendant of another
488     * attributeType.
489     *
490     * @param ancestor the perspective ancestor to check
491     * @return true if this AttributeType truly descends from the ancestor
492     */
493    public boolean isDescendantOf( AttributeType ancestor )
494    {
495        if ( ( ancestor == null ) || equals( ancestor ) )
496        {
497            return false;
498        }
499
500        return isAncestorOrEqual( ancestor, this );
501    }
502
503
504    /**
505     * Recursive method which checks to see if a descendant is really an ancestor or if the two
506     * are equal.
507     *
508     * @param ancestor the possible ancestor of the descendant
509     * @param descendant the possible descendant of the ancestor
510     * @return true if the ancestor equals the descendant or if the descendant is really
511     * a subtype of the ancestor. otherwise false
512     */
513    private boolean isAncestorOrEqual( AttributeType ancestor, AttributeType descendant )
514    {
515        if ( ( ancestor == null ) || ( descendant == null ) )
516        {
517            return false;
518        }
519
520        if ( ancestor.equals( descendant ) )
521        {
522            return true;
523        }
524
525        return isAncestorOrEqual( ancestor, descendant.getSuperior() );
526    }
527
528
529    /**
530     * {@inheritDoc}
531     */
532    public String toString()
533    {
534        return SchemaObjectRenderer.OPEN_LDAP_SCHEMA_RENDERER.render( this );
535    }
536
537
538    /**
539     * {@inheritDoc}
540     */
541    public AttributeType copy()
542    {
543        MutableAttributeType copy = new MutableAttributeType( oid );
544
545        // Copy the SchemaObject common data
546        copy.copy( this );
547
548        // Copy the canUserModify flag
549        copy.canUserModify = canUserModify;
550
551        // Copy the isCollective flag
552        copy.isCollective = isCollective;
553
554        // Copy the isSingleValue flag
555        copy.isSingleValued = isSingleValued;
556
557        // Copy the USAGE type
558        copy.usage = usage;
559
560        // All the references to other Registries object are set to null,
561        // all the OIDs are copied
562        // The EQUALITY MR
563        copy.equality = null;
564        copy.equalityOid = equalityOid;
565
566        // The ORDERING MR
567        copy.ordering = null;
568        copy.orderingOid = orderingOid;
569
570        // The SUBSTR MR
571        copy.substring = null;
572        copy.substringOid = substringOid;
573
574        // The SUP AT
575        copy.superior = null;
576        copy.superiorOid = superiorOid;
577
578        // The SYNTAX
579        copy.syntax = null;
580        copy.syntaxOid = syntaxOid;
581        copy.syntaxLength = syntaxLength;
582
583        return copy;
584    }
585
586
587    /**
588     * {@inheritDoc}
589     */
590    public boolean equals( Object o )
591    {
592        if ( !super.equals( o ) )
593        {
594            return false;
595        }
596
597        if ( !( o instanceof AttributeType ) )
598        {
599            return false;
600        }
601
602        AttributeType that = ( AttributeType ) o;
603
604        // The COLLECTIVE
605        if ( isCollective != that.isCollective )
606        {
607            return false;
608        }
609
610        // The SINGLE_VALUE
611        if ( isSingleValued != that.isSingleValued )
612        {
613            return false;
614        }
615
616        // The NO_USER_MODIFICATION
617        if ( canUserModify != that.canUserModify )
618        {
619            return false;
620        }
621
622        // The USAGE
623        if ( usage != that.usage )
624        {
625            return false;
626        }
627
628        // The equality
629        if ( !compareOid( equalityOid, that.equalityOid ) )
630        {
631            return false;
632        }
633
634        if ( equality != null )
635        {
636            if ( !equality.equals( that.equality ) )
637            {
638                return false;
639            }
640        }
641        else
642        {
643            if ( that.equality != null )
644            {
645                return false;
646            }
647        }
648
649        // The ordering
650        if ( !compareOid( orderingOid, that.orderingOid ) )
651        {
652            return false;
653        }
654
655        if ( ordering != null )
656        {
657            if ( !ordering.equals( that.ordering ) )
658            {
659                return false;
660            }
661        }
662        else
663        {
664            if ( that.ordering != null )
665            {
666                return false;
667            }
668        }
669
670        // The substring
671        if ( !compareOid( substringOid, that.substringOid ) )
672        {
673            return false;
674        }
675
676        if ( substring != null )
677        {
678            if ( !substring.equals( that.substring ) )
679            {
680                return false;
681            }
682        }
683        else
684        {
685            if ( that.substring != null )
686            {
687                return false;
688            }
689        }
690
691        // The superior
692        if ( !compareOid( superiorOid, that.superiorOid ) )
693        {
694            return false;
695        }
696
697        if ( superior != null )
698        {
699            if ( !superior.equals( that.superior ) )
700            {
701                return false;
702            }
703        }
704        else
705        {
706            if ( that.superior != null )
707            {
708                return false;
709            }
710        }
711
712        // The syntax
713        if ( !compareOid( syntaxOid, that.syntaxOid ) )
714        {
715            return false;
716        }
717
718        if ( syntaxLength != that.syntaxLength )
719        {
720            return false;
721        }
722
723        if ( syntax == null )
724        {
725            return that.syntax == null;
726        }
727
728        if ( syntax.equals( that.syntax ) )
729        {
730            return syntaxLength == that.syntaxLength;
731        }
732        else
733        {
734            return false;
735        }
736    }
737}