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