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
022import org.apache.directory.api.i18n.I18n;
023
024/**
025 * An attributeType specification. attributeType specifications describe the
026 * nature of attributes within the directory. The attributeType specification's
027 * properties are accessible through this interface.
028 * <p>
029 * According to ldapbis [MODELS]:
030 * </p>
031 *
032 * <pre>
033 *  4.1.2. Attribute Types
034 *
035 *    Attribute Type definitions are written according to the ABNF:
036 *
037 *      AttributeTypeDescription = LPAREN WSP
038 *          numericoid                   ; object identifier
039 *          [ SP &quot;NAME&quot; SP qdescrs ]     ; short names (descriptors)
040 *          [ SP &quot;DESC&quot; SP qdstring ]    ; description
041 *          [ SP &quot;OBSOLETE&quot; ]            ; not active
042 *          [ SP &quot;SUP&quot; SP oid ]          ; supertype
043 *          [ SP &quot;EQUALITY&quot; SP oid ]     ; equality matching rule
044 *          [ SP &quot;ORDERING&quot; SP oid ]     ; ordering matching rule
045 *          [ SP &quot;SUBSTR&quot; SP oid ]       ; substrings matching rule
046 *          [ SP &quot;SYNTAX&quot; SP noidlen ]   ; value syntax
047 *          [ SP &quot;SINGLE-VALUE&quot; ]        ; single-value
048 *          [ SP &quot;COLLECTIVE&quot; ]          ; collective
049 *          [ SP &quot;NO-USER-MODIFICATION&quot; ]; not user modifiable
050 *          [ SP &quot;USAGE&quot; SP usage ]      ; usage
051 *          extensions WSP RPAREN        ; extensions
052 *
053 *      usage = &quot;userApplications&quot;     / ; user
054 *              &quot;directoryOperation&quot;   / ; directory operational
055 *              &quot;distributedOperation&quot; / ; DSA-shared operational
056 *              &quot;dSAOperation&quot;           ; DSA-specific operational
057 *
058 *    where:
059 *      [numericoid] is object identifier assigned to this attribute type;
060 *      NAME [qdescrs] are short names (descriptors) identifying this
061 *          attribute type;
062 *      DESC [qdstring] is a short descriptive string;
063 *      OBSOLETE indicates this attribute type is not active;
064 *      SUP oid specifies the direct supertype of this type;
065 *      EQUALITY, ORDERING, SUBSTRING provide the oid of the equality,
066 *          ordering, and substrings matching rules, respectively;
067 *      SYNTAX identifies value syntax by object identifier and may suggest
068 *          a minimum upper bound;
069 *      COLLECTIVE indicates this attribute type is collective [X.501];
070 *      NO-USER-MODIFICATION indicates this attribute type is not user
071 *          modifiable;
072 *      USAGE indicates the application of this attribute type; and
073 *      [extensions] describe extensions.
074 *
075 *    Each attribute type description must contain at least one of the SUP
076 *    or SYNTAX fields.
077 *
078 *    Usage of userApplications, the default, indicates that attributes of
079 *    this type represent user information.  That is, they are user
080 *    attributes.
081 *
082 *    COLLECTIVE requires usage userApplications.  Use of collective
083 *    attribute types in LDAP is not discussed in this technical
084 *    specification.
085 *
086 *    A usage of directoryOperation, distributedOperation, or dSAOperation
087 *    indicates that attributes of this type represent operational and/or
088 *    administrative information.  That is, they are operational attributes.
089 *
090 *    directoryOperation usage indicates that the attribute of this type is
091 *    a directory operational attribute.  distributedOperation usage
092 *    indicates that the attribute of this DSA-shared usage operational
093 *    attribute.  dSAOperation usage indicates that the attribute of this
094 *    type is a DSA-specific operational attribute.
095 *
096 *    NO-USER-MODIFICATION requires an operational usage.
097 *
098 *    Note that the [AttributeTypeDescription] does not list the matching
099 *    rules which can be used with that attribute type in an extensibleMatch
100 *    search filter.  This is done using the 'matchingRuleUse' attribute
101 *    described in Section 4.1.4.
102 *
103 *    This document refines the schema description of X.501 by requiring
104 *    that the SYNTAX field in an [AttributeTypeDescription] be a string
105 *    representation of an object identifier for the LDAP string syntax
106 *    definition with an optional indication of the suggested minimum bound
107 *    of a value of this attribute.
108 *
109 *    A suggested minimum upper bound on the number of characters in a value
110 *    with a string-based syntax, or the number of bytes in a value for all
111 *    other syntaxes, may be indicated by appending this bound count inside
112 *    of curly braces following the syntax's OBJECT IDENTIFIER in an
113 *
114 *    Attribute Type Description.  This bound is not part of the syntax name
115 *    itself.  For instance, &quot;1.3.6.4.1.1466.0{64}&quot; suggests that server
116 *    implementations should allow a string to be 64 characters long,
117 *    although they may allow longer strings.  Note that a single character
118 *    of the Directory String syntax may be encoded in more than one octet
119 *    since UTF-8 is a variable-length encoding.
120 * </pre>
121 *
122 * @see <a href="http://www.faqs.org/rfcs/rfc2252.html">RFC 2252 Section 4.2</a>
123 * @see <a
124 *      href="http://www.ietf.org/internet-drafts/draft-ietf-ldapbis-models-11.txt">
125 *      ldapbis [MODELS]</a>
126 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
127 */
128public class AttributeType extends AbstractSchemaObject implements Cloneable
129{
130    /** The mandatory serialVersionUID */
131    public static final long serialVersionUID = 1L;
132
133    /** The syntax OID associated with this AttributeType */
134    protected String syntaxOid;
135
136    /** The syntax associated with the syntaxID */
137    protected LdapSyntax syntax;
138
139    /** The equality OID associated with this AttributeType */
140    protected String equalityOid;
141
142    /** The equality MatchingRule associated with the equalityID */
143    protected MatchingRule equality;
144
145    /** The substring OID associated with this AttributeType */
146    protected String substringOid;
147
148    /** The substring MatchingRule associated with the substringID */
149    protected MatchingRule substring;
150
151    /** The ordering OID associated with this AttributeType */
152    protected String orderingOid;
153
154    /** The ordering MatchingRule associated with the orderingID */
155    protected MatchingRule ordering;
156
157    /** The superior AttributeType OID */
158    protected String superiorOid;
159
160    /** The superior AttributeType */
161    protected AttributeType superior;
162
163    /** whether or not this type is single valued */
164    protected boolean isSingleValued = false;
165
166    /** whether or not this type is a collective attribute */
167    protected boolean isCollective = false;
168
169    /** whether or not this type can be modified by directory users */
170    protected boolean canUserModify = true;
171
172    /** the usage for this attributeType */
173    protected UsageEnum usage = UsageEnum.USER_APPLICATIONS;
174
175    /** the length of this attribute in bytes */
176    protected long syntaxLength = 0L;
177    
178    /** A flag set when the SchemaManager is in relaxed mode */
179    private boolean isRelaxed = false;
180
181
182    /**
183     * Creates a AttributeType object using a unique OID.
184     *
185     * @param oid the OID for this AttributeType
186     */
187    public AttributeType( String oid )
188    {
189        super( SchemaObjectType.ATTRIBUTE_TYPE, oid );
190    }
191
192
193    /**
194     * Gets whether or not this AttributeType is single-valued.
195     *
196     * @return true if only one value can exist for this AttributeType, false
197     *         otherwise
198     */
199    public boolean isSingleValued()
200    {
201        return isSingleValued;
202    }
203
204
205    /**
206     * Tells if this AttributeType is Single Valued or not
207     *
208     * @param singleValued True if the AttributeType is single-valued
209     */
210    public void setSingleValued( boolean singleValued )
211    {
212        if ( locked )
213        {
214            throw new UnsupportedOperationException( I18n.err( I18n.ERR_13700_CANNOT_MODIFY_LOCKED_SCHEMA_OBJECT, getName() ) );
215        }
216
217        this.isSingleValued = singleValued;
218    }
219
220
221    /**
222     * Gets whether or not this AttributeType can be modified by a user.
223     *
224     * @return true if users can modify it, false if only the directory can.
225     */
226    public boolean isUserModifiable()
227    {
228        return canUserModify;
229    }
230
231
232    /**
233     * Tells if this AttributeType can be modified by a user or not
234     *
235     * @param userModifiable The flag to set
236     */
237    public void setUserModifiable( boolean userModifiable )
238    {
239        if ( locked )
240        {
241            throw new UnsupportedOperationException( I18n.err( I18n.ERR_13700_CANNOT_MODIFY_LOCKED_SCHEMA_OBJECT, getName() ) );
242        }
243
244        this.canUserModify = userModifiable;
245    }
246
247
248    /**
249     * Gets whether or not this AttributeType is a collective attribute.
250     *
251     * @return true if the attribute is collective, false otherwise
252     */
253    public boolean isCollective()
254    {
255        return isCollective;
256    }
257
258
259    /**
260     * Sets the collective flag
261     *
262     * @param collective The new value to set
263     */
264    public void setCollective( boolean collective )
265    {
266        if ( locked )
267        {
268            throw new UnsupportedOperationException( I18n.err( I18n.ERR_13700_CANNOT_MODIFY_LOCKED_SCHEMA_OBJECT, getName() ) );
269        }
270
271        this.isCollective = collective;
272    }
273
274
275    /**
276     * @return Tells if the AttributeType is relaxed (the SyntaxChecker will not be activated)
277     */
278    public boolean isRelaxed()
279    {
280        return isRelaxed;
281    }
282
283
284    /**
285     * Set this AttributeType mode to relaxed
286     * 
287     * @param isRelaxed <tt>true</tt> if the syntax checker for this AttributeType should not be activated
288     */
289    public void setRelaxed( boolean isRelaxed )
290    {
291        this.isRelaxed = isRelaxed;
292    }
293
294
295    /**
296     * Determines the usage for this AttributeType.
297     *
298     * @return a type safe UsageEnum
299     */
300    public UsageEnum getUsage()
301    {
302        return usage;
303    }
304
305
306    /**
307     * Sets the AttributeType usage, one of :
308     * <ul>
309     *   <li>USER_APPLICATIONS</li>
310     *   <li>DIRECTORY_OPERATION</li>
311     *   <li>DISTRIBUTED_OPERATION</li>
312     *   <li>DSA_OPERATION</li>
313     * </ul>
314     * 
315     * @see UsageEnum
316     * @param usage The AttributeType usage
317     */
318    public void setUsage( UsageEnum usage )
319    {
320        if ( locked )
321        {
322            throw new UnsupportedOperationException( I18n.err( I18n.ERR_13700_CANNOT_MODIFY_LOCKED_SCHEMA_OBJECT, getName() ) );
323        }
324
325        this.usage = usage;
326    }
327
328
329    /**
330     * Gets a length limit for this AttributeType.
331     *
332     * @return the length of the attribute
333     */
334    public long getSyntaxLength()
335    {
336        return syntaxLength;
337    }
338
339
340    /**
341     * Sets the length limit of this AttributeType based on its associated
342     * syntax.
343     *
344     * @param length the new length to set
345     */
346    public void setSyntaxLength( long length )
347    {
348        if ( locked )
349        {
350            throw new UnsupportedOperationException( I18n.err( I18n.ERR_13700_CANNOT_MODIFY_LOCKED_SCHEMA_OBJECT, getName() ) );
351        }
352
353        this.syntaxLength = length;
354    }
355
356
357    /**
358     * Gets the the superior AttributeType of this AttributeType.
359     *
360     * @return the superior AttributeType for this AttributeType
361     */
362    public AttributeType getSuperior()
363    {
364        return superior;
365    }
366
367
368    /**
369     * Gets the OID of the superior AttributeType for this AttributeType.
370     *
371     * @return The OID of the superior AttributeType for this AttributeType.
372     */
373    public String getSuperiorOid()
374    {
375        return superiorOid;
376    }
377
378
379    /**
380     * Sets the superior for this AttributeType
381     *
382     * @param superior The superior for this AttributeType
383     */
384    public void setSuperior( AttributeType superior )
385    {
386        if ( locked )
387        {
388            throw new UnsupportedOperationException( I18n.err( I18n.ERR_13700_CANNOT_MODIFY_LOCKED_SCHEMA_OBJECT, getName() ) );
389        }
390
391        this.superior = superior;
392        this.superiorOid = superior.getOid();
393    }
394
395
396    /**
397     * Sets the superior oid for this AttributeType
398     *
399     * @param newSuperiorOid The superior oid for this AttributeType
400     */
401    public void setSuperior( String newSuperiorOid )
402    {
403        if ( locked )
404        {
405            throw new UnsupportedOperationException( I18n.err( I18n.ERR_13700_CANNOT_MODIFY_LOCKED_SCHEMA_OBJECT, getName() ) );
406        }
407
408        this.superiorOid = newSuperiorOid;
409    }
410
411
412    /**
413     * Sets the superior AttributeType OID of this AttributeType
414     *
415     * @param superiorOid The superior AttributeType OID of this AttributeType
416     */
417    public void setSuperiorOid( String superiorOid )
418    {
419        if ( locked )
420        {
421            throw new UnsupportedOperationException( I18n.err( I18n.ERR_13700_CANNOT_MODIFY_LOCKED_SCHEMA_OBJECT, getName() ) );
422        }
423
424        this.superiorOid = superiorOid;
425    }
426
427
428    /**
429     * Gets the Name of the superior AttributeType for this AttributeType.
430     *
431     * @return The Name of the superior AttributeType for this AttributeType.
432     */
433    public String getSuperiorName()
434    {
435        if ( superior != null )
436        {
437            return superior.getName();
438        }
439        else
440        {
441            return superiorOid;
442        }
443    }
444
445
446    /**
447     * Gets the Syntax for this AttributeType's values.
448     *
449     * @return the value syntax
450     */
451    public LdapSyntax getSyntax()
452    {
453        return syntax;
454    }
455
456
457    /**
458     * Sets the Syntax for this AttributeType
459     *
460     * @param syntax The Syntax for this AttributeType
461     */
462    public void setSyntax( LdapSyntax syntax )
463    {
464        if ( locked )
465        {
466            throw new UnsupportedOperationException( I18n.err( I18n.ERR_13700_CANNOT_MODIFY_LOCKED_SCHEMA_OBJECT, getName() ) );
467        }
468
469        this.syntax = syntax;
470        this.syntaxOid = syntax.getOid();
471    }
472
473
474    /**
475     * Gets the Syntax name for this AttributeType's values.
476     *
477     * @return the value syntax name
478     */
479    public String getSyntaxName()
480    {
481        if ( syntax != null )
482        {
483            return syntax.getName();
484        }
485        else
486        {
487            return syntaxOid;
488        }
489    }
490
491
492    /**
493     * Gets the Syntax OID for this AttributeType's values.
494     *
495     * @return the value syntax's OID
496     */
497    public String getSyntaxOid()
498    {
499        return syntaxOid;
500    }
501
502
503    /**
504     * Sets the Syntax OID for this AttributeType
505     *
506     * @param syntaxOid The syntax OID for this AttributeType
507     */
508    public void setSyntaxOid( String syntaxOid )
509    {
510        if ( locked )
511        {
512            throw new UnsupportedOperationException( I18n.err( I18n.ERR_13700_CANNOT_MODIFY_LOCKED_SCHEMA_OBJECT, getName() ) );
513        }
514
515        this.syntaxOid = syntaxOid;
516    }
517
518
519    /**
520     * Gets the MatchingRule for this AttributeType used for equality matching.
521     *
522     * @return the equality matching rule
523     */
524    public MatchingRule getEquality()
525    {
526        return equality;
527    }
528
529
530    /**
531     * Sets the Equality MR for this AttributeType
532     *
533     * @param equality The Equality MR for this AttributeType
534     */
535    public void setEquality( MatchingRule equality )
536    {
537        if ( locked )
538        {
539            throw new UnsupportedOperationException( I18n.err( I18n.ERR_13700_CANNOT_MODIFY_LOCKED_SCHEMA_OBJECT, getName() ) );
540        }
541
542        this.equality = equality;
543        this.equalityOid = equality.getOid();
544    }
545
546
547    /**
548     * Gets the Equality OID for this AttributeType's values.
549     *
550     * @return the value Equality's OID
551     */
552    public String getEqualityOid()
553    {
554        return equalityOid;
555    }
556
557
558    /**
559     * Sets the Equality OID for this AttributeType
560     *
561     * @param equalityOid The Equality OID for this AttributeType
562     */
563    public void setEqualityOid( String equalityOid )
564    {
565        if ( locked )
566        {
567            throw new UnsupportedOperationException( I18n.err( I18n.ERR_13700_CANNOT_MODIFY_LOCKED_SCHEMA_OBJECT, getName() ) );
568        }
569
570        this.equalityOid = equalityOid;
571    }
572
573
574    /**
575     * Gets the Equality Name for this AttributeType's values.
576     *
577     * @return the value Equality's Name
578     */
579    public String getEqualityName()
580    {
581        if ( equality != null )
582        {
583            return equality.getName();
584        }
585        else
586        {
587            return equalityOid;
588        }
589    }
590
591
592    /**
593     * Gets the MatchingRule for this AttributeType used for Ordering matching.
594     *
595     * @return the Ordering matching rule
596     */
597    public MatchingRule getOrdering()
598    {
599        return ordering;
600    }
601
602
603    /**
604     * Sets the Ordering MR for this AttributeType
605     *
606     * @param ordering The Ordering MR for this AttributeType
607     */
608    public void setOrdering( MatchingRule ordering )
609    {
610        if ( locked )
611        {
612            throw new UnsupportedOperationException( I18n.err( I18n.ERR_13700_CANNOT_MODIFY_LOCKED_SCHEMA_OBJECT, getName() ) );
613        }
614
615        this.ordering = ordering;
616        this.orderingOid = ordering.getOid();
617    }
618
619
620    /**
621     * Gets the MatchingRule name for this AttributeType used for Ordering matching.
622     *
623     * @return the Ordering matching rule name
624     */
625    public String getOrderingName()
626    {
627        if ( ordering != null )
628        {
629            return ordering.getName();
630        }
631        else
632        {
633            return orderingOid;
634        }
635    }
636
637
638    /**
639     * Gets the Ordering OID for this AttributeType's values.
640     *
641     * @return the value Equality's OID
642     */
643    public String getOrderingOid()
644    {
645        return orderingOid;
646    }
647
648
649    /**
650     * Sets the Ordering OID for this AttributeType
651     *
652     * @param orderingOid The Ordering OID for this AttributeType
653     */
654    public void setOrderingOid( String orderingOid )
655    {
656        if ( locked )
657        {
658            throw new UnsupportedOperationException( I18n.err( I18n.ERR_13700_CANNOT_MODIFY_LOCKED_SCHEMA_OBJECT, getName() ) );
659        }
660
661        this.orderingOid = orderingOid;
662    }
663
664
665    /**
666     * Gets the MatchingRule for this AttributeType used for Substr matching.
667     *
668     * @return the Substr matching rule
669     */
670    public MatchingRule getSubstring()
671    {
672        return substring;
673    }
674
675
676    /**
677     * Sets the Substr MR for this AttributeType
678     *
679     * @param substring The Substr MR for this AttributeType
680     */
681    public void setSubstring( MatchingRule substring )
682    {
683        if ( locked )
684        {
685            throw new UnsupportedOperationException( I18n.err( I18n.ERR_13700_CANNOT_MODIFY_LOCKED_SCHEMA_OBJECT, getName() ) );
686        }
687
688        this.substring = substring;
689        this.substringOid = substring.getOid();
690    }
691
692
693    /**
694     * Gets the MatchingRule name for this AttributeType used for Substring matching.
695     *
696     * @return the Substring matching rule name
697     */
698    public String getSubstringName()
699    {
700        if ( substring != null )
701        {
702            return substring.getName();
703        }
704        else
705        {
706            return substringOid;
707        }
708    }
709
710
711    /**
712     * Gets the Substr OID for this AttributeType's values.
713     *
714     * @return the value Substr's OID
715     */
716    public String getSubstringOid()
717    {
718        return substringOid;
719    }
720
721
722    /**
723     * Sets the Substr OID for this AttributeType
724     *
725     * @param substrOid The Substr OID for this AttributeType
726     */
727    public void setSubstringOid( String substrOid )
728    {
729        if ( locked )
730        {
731            throw new UnsupportedOperationException( I18n.err( I18n.ERR_13700_CANNOT_MODIFY_LOCKED_SCHEMA_OBJECT, getName() ) );
732        }
733
734        this.substringOid = substrOid;
735    }
736
737
738    /**
739     * Tells if the attributeType is a USER attribute or not
740     * @return true if this is a USER attributeType
741     */
742    public boolean isUser()
743    {
744        return usage == UsageEnum.USER_APPLICATIONS;
745    }
746
747
748    /**
749     * Tells if the attributeType is an OPERATIONAL attribute or not
750     * @return true if this is an OPERATIONAL attributeType
751     */
752    public boolean isOperational()
753    {
754        return usage != UsageEnum.USER_APPLICATIONS;
755    }
756
757
758    /**
759     * Checks to see if this AttributeType is the ancestor of another
760     * attributeType.
761     *
762     * @param descendant the perspective descendant to check
763     * @return true if the descendant is truly a derived from this AttributeType
764     */
765    public boolean isAncestorOf( AttributeType descendant )
766    {
767        if ( ( descendant == null ) || this.equals( descendant ) )
768        {
769            return false;
770        }
771
772        return isAncestorOrEqual( this, descendant );
773    }
774    
775    
776    /**
777     * Tells if an AttributeType is HumanReadable or not, depending on its Syntax.
778     * 
779     * @return <tt>true</tt> if the AttributeType is Human Readable.
780     */
781    public boolean isHR()
782    {
783        return ( syntax != null ) && ( syntax.isHumanReadable() );
784    }
785
786
787    /**
788     * Checks to see if this AttributeType is the descendant of another
789     * attributeType.
790     *
791     * @param ancestor the perspective ancestor to check
792     * @return true if this AttributeType truly descends from the ancestor
793     */
794    public boolean isDescendantOf( AttributeType ancestor )
795    {
796        if ( ( ancestor == null ) || equals( ancestor ) )
797        {
798            return false;
799        }
800
801        return isAncestorOrEqual( ancestor, this );
802    }
803
804
805    /**
806     * Recursive method which checks to see if a descendant is really an ancestor or if the two
807     * are equal.
808     *
809     * @param ancestor the possible ancestor of the descendant
810     * @param descendant the possible descendant of the ancestor
811     * @return true if the ancestor equals the descendant or if the descendant is really
812     * a subtype of the ancestor. otherwise false
813     */
814    private boolean isAncestorOrEqual( AttributeType ancestor, AttributeType descendant )
815    {
816        if ( ( ancestor == null ) || ( descendant == null ) )
817        {
818            return false;
819        }
820
821        if ( ancestor.equals( descendant ) )
822        {
823            return true;
824        }
825
826        return isAncestorOrEqual( ancestor, descendant.getSuperior() );
827    }
828
829
830    /**
831     * {@inheritDoc}
832     */
833    @Override
834    public String toString()
835    {
836        return SchemaObjectRenderer.OPEN_LDAP_SCHEMA_RENDERER.render( this );
837    }
838
839
840    /**
841     * {@inheritDoc}
842     */
843    @Override
844    public AttributeType copy()
845    {
846        AttributeType copy = new AttributeType( oid );
847
848        // Copy the SchemaObject common data
849        copy.copy( this );
850
851        // Copy the canUserModify flag
852        copy.canUserModify = canUserModify;
853
854        // Copy the isCollective flag
855        copy.isCollective = isCollective;
856
857        // Copy the isSingleValue flag
858        copy.isSingleValued = isSingleValued;
859
860        // Copy the USAGE type
861        copy.usage = usage;
862
863        // All the references to other Registries object are set to null,
864        // all the OIDs are copied
865        // The EQUALITY MR
866        copy.equality = null;
867        copy.equalityOid = equalityOid;
868
869        // The ORDERING MR
870        copy.ordering = null;
871        copy.orderingOid = orderingOid;
872
873        // The SUBSTR MR
874        copy.substring = null;
875        copy.substringOid = substringOid;
876
877        // The SUP AT
878        copy.superior = null;
879        copy.superiorOid = superiorOid;
880
881        // The SYNTAX
882        copy.syntax = null;
883        copy.syntaxOid = syntaxOid;
884        copy.syntaxLength = syntaxLength;
885        
886        // The relaxed flag
887        copy.setRelaxed( isRelaxed );
888
889        return copy;
890    }
891    
892    
893    /**
894     * {@inheritDoc}
895     */
896    @Override
897    public int hashCode()
898    {
899        int ath = super.hashCode();
900        
901        // USER_MODIFY
902        ath += ath * 17 + ( canUserModify ? 1 : 0 );
903        
904        // COLLECTIVE
905        ath += ath * 17 + ( isCollective ? 1 : 0 );
906        
907        // MULTI_VALUED
908        ath += ath * 17 + ( isSingleValued ? 1 : 0 );
909        
910        // The syntax
911        if ( syntax != null )
912        {
913            ath += ath * 17 + syntax.hashCode();
914        }
915
916        // The equality matching rule if any
917        if ( equality != null )
918        {
919            ath += ath * 17 + equality.hashCode();
920        }
921
922        // The substring matching rule if any
923        if ( substring != null )
924        {
925            ath += ath * 17 + substring.hashCode();
926        }
927        
928        // The superior if any
929        if ( superior != null )
930        {
931            ath += ath * 17 + superior.hashCode();
932        }
933        
934        // The ordering if any
935        if ( ordering != null )
936        {
937            ath += ath * 17 + ordering.hashCode();
938        }
939        
940        // Last, not least, the usage
941        ath += ath * 17 + usage.getValue();
942        
943        return ath;
944    }
945    
946    
947    /**
948     * {@inheritDoc}
949     */
950    @Override
951    public boolean equals( Object o )
952    {
953        if ( this == o )
954        {
955            return true;
956        }
957        
958        if ( !super.equals( o ) )
959        {
960            return false;
961        }
962
963        if ( !( o instanceof AttributeType ) )
964        {
965            return false;
966        }
967
968        AttributeType that = ( AttributeType ) o;
969
970        // The COLLECTIVE
971        if ( isCollective != that.isCollective )
972        {
973            return false;
974        }
975
976        // The SINGLE_VALUE
977        if ( isSingleValued != that.isSingleValued )
978        {
979            return false;
980        }
981
982        // The NO_USER_MODIFICATION
983        if ( canUserModify != that.canUserModify )
984        {
985            return false;
986        }
987
988        // The USAGE
989        if ( usage != that.usage )
990        {
991            return false;
992        }
993
994        // The equality
995        if ( !compareOid( equalityOid, that.equalityOid ) )
996        {
997            return false;
998        }
999
1000        if ( equality != null )
1001        {
1002            if ( !equality.equals( that.equality ) )
1003            {
1004                return false;
1005            }
1006        }
1007        else
1008        {
1009            if ( that.equality != null )
1010            {
1011                return false;
1012            }
1013        }
1014
1015        // The ordering
1016        if ( !compareOid( orderingOid, that.orderingOid ) )
1017        {
1018            return false;
1019        }
1020
1021        if ( ordering != null )
1022        {
1023            if ( !ordering.equals( that.ordering ) )
1024            {
1025                return false;
1026            }
1027        }
1028        else
1029        {
1030            if ( that.ordering != null )
1031            {
1032                return false;
1033            }
1034        }
1035
1036        // The substring
1037        if ( !compareOid( substringOid, that.substringOid ) )
1038        {
1039            return false;
1040        }
1041
1042        if ( substring != null )
1043        {
1044            if ( !substring.equals( that.substring ) )
1045            {
1046                return false;
1047            }
1048        }
1049        else
1050        {
1051            if ( that.substring != null )
1052            {
1053                return false;
1054            }
1055        }
1056
1057        // The superior
1058        if ( !compareOid( superiorOid, that.superiorOid ) )
1059        {
1060            return false;
1061        }
1062
1063        if ( superior != null )
1064        {
1065            if ( !superior.equals( that.superior ) )
1066            {
1067                return false;
1068            }
1069        }
1070        else
1071        {
1072            if ( that.superior != null )
1073            {
1074                return false;
1075            }
1076        }
1077
1078        // The syntax
1079        if ( !compareOid( syntaxOid, that.syntaxOid ) )
1080        {
1081            return false;
1082        }
1083
1084        if ( syntaxLength != that.syntaxLength )
1085        {
1086            return false;
1087        }
1088
1089        if ( syntax == null )
1090        {
1091            return that.syntax == null;
1092        }
1093
1094        if ( syntax.equals( that.syntax ) )
1095        {
1096            return syntaxLength == that.syntaxLength;
1097        }
1098        else
1099        {
1100            return false;
1101        }
1102    }
1103
1104
1105    /**
1106     * {@inheritDoc}
1107     */
1108    @Override
1109    public void clear()
1110    {
1111        // Clear the common elements
1112        super.clear();
1113
1114        // Clear the references
1115        equality = null;
1116        ordering = null;
1117        substring = null;
1118        superior = null;
1119        syntax = null;
1120    }
1121}