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     */
020    package org.apache.directory.shared.ldap.schema;
021    
022    
023    import java.util.HashSet;
024    import java.util.List;
025    import java.util.Set;
026    
027    import javax.naming.NamingException;
028    
029    import org.apache.directory.shared.i18n.I18n;
030    import org.apache.directory.shared.ldap.exception.LdapSchemaViolationException;
031    import org.apache.directory.shared.ldap.message.ResultCodeEnum;
032    import org.apache.directory.shared.ldap.schema.registries.AttributeTypeRegistry;
033    import org.apache.directory.shared.ldap.schema.registries.Registries;
034    import org.slf4j.Logger;
035    import org.slf4j.LoggerFactory;
036    
037    
038    /**
039     * An attributeType specification. attributeType specifications describe the
040     * nature of attributes within the directory. The attributeType specification's
041     * properties are accessible through this interface.
042     * <p>
043     * According to ldapbis [MODELS]:
044     * </p>
045     * 
046     * <pre>
047     *  4.1.2. Attribute Types
048     *  
049     *    Attribute Type definitions are written according to the ABNF:
050     *  
051     *      AttributeTypeDescription = LPAREN WSP
052     *          numericoid                   ; object identifier
053     *          [ SP &quot;NAME&quot; SP qdescrs ]     ; short names (descriptors)
054     *          [ SP &quot;DESC&quot; SP qdstring ]    ; description
055     *          [ SP &quot;OBSOLETE&quot; ]            ; not active
056     *          [ SP &quot;SUP&quot; SP oid ]          ; supertype
057     *          [ SP &quot;EQUALITY&quot; SP oid ]     ; equality matching rule
058     *          [ SP &quot;ORDERING&quot; SP oid ]     ; ordering matching rule
059     *          [ SP &quot;SUBSTR&quot; SP oid ]       ; substrings matching rule
060     *          [ SP &quot;SYNTAX&quot; SP noidlen ]   ; value syntax
061     *          [ SP &quot;SINGLE-VALUE&quot; ]        ; single-value
062     *          [ SP &quot;COLLECTIVE&quot; ]          ; collective
063     *          [ SP &quot;NO-USER-MODIFICATION&quot; ]; not user modifiable
064     *          [ SP &quot;USAGE&quot; SP usage ]      ; usage
065     *          extensions WSP RPAREN        ; extensions
066     *  
067     *      usage = &quot;userApplications&quot;     / ; user
068     *              &quot;directoryOperation&quot;   / ; directory operational
069     *              &quot;distributedOperation&quot; / ; DSA-shared operational
070     *              &quot;dSAOperation&quot;           ; DSA-specific operational
071     *  
072     *    where:
073     *      [numericoid] is object identifier assigned to this attribute type;
074     *      NAME [qdescrs] are short names (descriptors) identifying this
075     *          attribute type;
076     *      DESC [qdstring] is a short descriptive string;
077     *      OBSOLETE indicates this attribute type is not active;
078     *      SUP oid specifies the direct supertype of this type;
079     *      EQUALITY, ORDERING, SUBSTRING provide the oid of the equality,
080     *          ordering, and substrings matching rules, respectively;
081     *      SYNTAX identifies value syntax by object identifier and may suggest
082     *          a minimum upper bound;
083     *      COLLECTIVE indicates this attribute type is collective [X.501];
084     *      NO-USER-MODIFICATION indicates this attribute type is not user
085     *          modifiable;
086     *      USAGE indicates the application of this attribute type; and
087     *      [extensions] describe extensions.
088     *  
089     *    Each attribute type description must contain at least one of the SUP
090     *    or SYNTAX fields.
091     *  
092     *    Usage of userApplications, the default, indicates that attributes of
093     *    this type represent user information.  That is, they are user
094     *    attributes.
095     *  
096     *    COLLECTIVE requires usage userApplications.  Use of collective
097     *    attribute types in LDAP is not discussed in this technical
098     *    specification.
099     *  
100     *    A usage of directoryOperation, distributedOperation, or dSAOperation
101     *    indicates that attributes of this type represent operational and/or
102     *    administrative information.  That is, they are operational attributes.
103     *  
104     *    directoryOperation usage indicates that the attribute of this type is
105     *    a directory operational attribute.  distributedOperation usage
106     *    indicates that the attribute of this DSA-shared usage operational
107     *    attribute.  dSAOperation usage indicates that the attribute of this
108     *    type is a DSA-specific operational attribute.
109     *  
110     *    NO-USER-MODIFICATION requires an operational usage.
111     *  
112     *    Note that the [AttributeTypeDescription] does not list the matching
113     *    rules which can be used with that attribute type in an extensibleMatch
114     *    search filter.  This is done using the 'matchingRuleUse' attribute
115     *    described in Section 4.1.4.
116     *  
117     *    This document refines the schema description of X.501 by requiring
118     *    that the SYNTAX field in an [AttributeTypeDescription] be a string
119     *    representation of an object identifier for the LDAP string syntax
120     *    definition with an optional indication of the suggested minimum bound
121     *    of a value of this attribute.
122     *  
123     *    A suggested minimum upper bound on the number of characters in a value
124     *    with a string-based syntax, or the number of bytes in a value for all
125     *    other syntaxes, may be indicated by appending this bound count inside
126     *    of curly braces following the syntax's OBJECT IDENTIFIER in an
127     *  
128     *    Attribute Type Description.  This bound is not part of the syntax name
129     *    itself.  For instance, &quot;1.3.6.4.1.1466.0{64}&quot; suggests that server
130     *    implementations should allow a string to be 64 characters long,
131     *    although they may allow longer strings.  Note that a single character
132     *    of the Directory String syntax may be encoded in more than one octet
133     *    since UTF-8 is a variable-length encoding.
134     * </pre>
135     * 
136     * @see <a href="http://www.faqs.org/rfcs/rfc2252.html">RFC 2252 Section 4.2</a>
137     * @see <a
138     *      href="http://www.ietf.org/internet-drafts/draft-ietf-ldapbis-models-11.txt">
139     *      ldapbis [MODELS]</a>
140     * @see DescriptionUtils#getDescription(AttributeType)
141     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
142     * @version $Rev: 919765 $
143     */
144    public class AttributeType extends AbstractSchemaObject implements Cloneable
145    {
146        /** A logger for this class */
147        private static final Logger LOG = LoggerFactory.getLogger( AttributeType.class );
148    
149        /** The serialVersionUID */
150        public static final long serialVersionUID = 1L;
151    
152        /** The syntax OID associated with this AttributeType */
153        private String syntaxOid;
154    
155        /** The syntax associated with the syntaxID */
156        private LdapSyntax syntax;
157    
158        /** The equality OID associated with this AttributeType */
159        private String equalityOid;
160    
161        /** The equality MatchingRule associated with the equalityID */
162        private MatchingRule equality;
163    
164        /** The substring OID associated with this AttributeType */
165        private String substringOid;
166    
167        /** The substring MatchingRule associated with the substringID */
168        private MatchingRule substring;
169    
170        /** The ordering OID associated with this AttributeType */
171        private String orderingOid;
172    
173        /** The ordering MatchingRule associated with the orderingID */
174        private MatchingRule ordering;
175    
176        /** The superior AttributeType OID */
177        private String superiorOid;
178    
179        /** The superior AttributeType */
180        private AttributeType superior;
181    
182        /** whether or not this type is single valued */
183        private boolean isSingleValued = false;
184    
185        /** whether or not this type is a collective attribute */
186        private boolean isCollective = false;
187    
188        /** whether or not this type can be modified by directory users */
189        private boolean canUserModify = true;
190    
191        /** the usage for this attributeType */
192        private UsageEnum usage = UsageEnum.USER_APPLICATIONS;
193    
194        /** the length of this attribute in bytes */
195        private int syntaxLength = 0;
196    
197    
198        /**
199         * Creates a AttributeType object using a unique OID.
200         * 
201         * @param oid the OID for this AttributeType
202         */
203        public AttributeType( String oid )
204        {
205            super( SchemaObjectType.ATTRIBUTE_TYPE, oid );
206        }
207    
208    
209        /**
210         * Build the Superior AttributeType reference for an AttributeType
211         */
212        private boolean buildSuperior( List<Throwable> errors, Registries registries )
213        {
214            AttributeType superior = null;
215            AttributeTypeRegistry attributeTypeRegistry = registries.getAttributeTypeRegistry();
216    
217            if ( superiorOid != null )
218            {
219                // This AT has a superior
220                try
221                {
222                    superior = attributeTypeRegistry.lookup( superiorOid );
223                }
224                catch ( Exception e )
225                {
226                    // Not allowed.
227                    String msg = I18n.err( I18n.ERR_04303, superiorOid, getName() );
228    
229                    Throwable error = new LdapSchemaViolationException( msg, ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX );
230                    errors.add( error );
231                    LOG.info( msg );
232    
233                    // Get out now
234                    return false;
235                }
236    
237                if ( superior != null )
238                {
239                    this.superior = superior;
240    
241                    // Recursively update the superior if not already done. We don't recurse
242                    // if the superior's superior is not null, as it means it has already been
243                    // handled.
244                    if ( superior.getSuperior() == null )
245                    {
246                        registries.buildReference( errors, superior );
247                    }
248    
249                    // Update the descendant MAP
250                    try
251                    {
252                        attributeTypeRegistry.registerDescendants( this, superior );
253                    }
254                    catch ( NamingException ne )
255                    {
256                        errors.add( ne );
257                        LOG.info( ne.getMessage() );
258                        return false;
259                    }
260    
261                    // Check for cycles now
262                    Set<String> superiors = new HashSet<String>();
263                    superiors.add( oid );
264                    AttributeType tmp = superior;
265                    boolean isOk = true;
266    
267                    while ( tmp != null )
268                    {
269                        if ( superiors.contains( tmp.getOid() ) )
270                        {
271                            // There is a cycle : bad bad bad !
272                            // Not allowed.
273                            String msg = I18n.err( I18n.ERR_04304, getName() );
274    
275                            Throwable error = new LdapSchemaViolationException( msg,
276                                ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX );
277                            errors.add( error );
278                            LOG.info( msg );
279                            isOk = false;
280    
281                            break;
282                        }
283                        else
284                        {
285                            superiors.add( tmp.getOid() );
286                            tmp = tmp.getSuperior();
287                        }
288                    }
289    
290                    superiors.clear();
291    
292                    return isOk;
293                }
294                else
295                {
296                    // Not allowed.
297                    String msg = I18n.err( I18n.ERR_04305, superiorOid, getName() );
298    
299                    Throwable error = new LdapSchemaViolationException( msg, ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX );
300                    errors.add( error );
301                    LOG.info( msg );
302    
303                    // Get out now
304                    return false;
305                }
306            }
307            else
308            {
309                // No superior, just return
310                return true;
311            }
312        }
313    
314    
315        /**
316         * Build the SYNTAX reference for an AttributeType
317         */
318        private void buildSyntax( List<Throwable> errors, Registries registries )
319        {
320            if ( syntaxOid != null )
321            {
322                LdapSyntax syntax = null;
323    
324                try
325                {
326                    syntax = registries.getLdapSyntaxRegistry().lookup( syntaxOid );
327                }
328                catch ( NamingException ne )
329                {
330                    // Not allowed.
331                    String msg = I18n.err( I18n.ERR_04306, syntaxOid, getName() );
332    
333                    Throwable error = new LdapSchemaViolationException( msg, ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX );
334                    errors.add( error );
335                    LOG.info( msg );
336                    return;
337                }
338    
339                if ( syntax != null )
340                {
341                    // Update the Syntax reference
342                    this.syntax = syntax;
343                }
344                else
345                {
346                    // Not allowed.
347                    String msg = I18n.err( I18n.ERR_04306, syntaxOid, getName() );
348    
349                    Throwable error = new LdapSchemaViolationException( msg, ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX );
350                    errors.add( error );
351                    LOG.info( msg );
352                    return;
353                }
354            }
355            else
356            {
357                // We inherit from the superior's syntax, if any
358                if ( superior != null )
359                {
360                    this.syntax = superior.getSyntax();
361                    this.syntaxOid = this.syntax.getOid();
362                }
363                else
364                {
365                    // Not allowed.
366                    String msg = I18n.err( I18n.ERR_04307, getName() );
367    
368                    Throwable error = new LdapSchemaViolationException( msg, ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX );
369                    errors.add( error );
370                    LOG.info( msg );
371                    return;
372                }
373            }
374        }
375    
376    
377        /**
378         * Build the EQUALITY MR reference for an AttributeType
379         */
380        private void buildEquality( List<Throwable> errors, Registries registries )
381        {
382            // The equality MR. It can be null
383            if ( equalityOid != null )
384            {
385                MatchingRule equality = null;
386    
387                try
388                {
389                    equality = registries.getMatchingRuleRegistry().lookup( equalityOid );
390                }
391                catch ( NamingException ne )
392                {
393                    // Not allowed.
394                    String msg = I18n.err( I18n.ERR_04308, equalityOid, getName() );
395    
396                    Throwable error = new LdapSchemaViolationException( msg, ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX );
397                    errors.add( error );
398                    LOG.info( msg );
399                    return;
400                }
401    
402                if ( equality != null )
403                {
404                    this.equality = equality;
405                }
406                else
407                {
408                    // Not allowed.
409                    String msg = I18n.err( I18n.ERR_04309, equalityOid, getName() );
410    
411                    Throwable error = new LdapSchemaViolationException( msg, ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX );
412                    errors.add( error );
413                    LOG.info( msg );
414                }
415            }
416            else
417            {
418                // If the AT has a superior, take its Equality MR if any
419                if ( ( superior != null ) && ( superior.getEquality() != null ) )
420                {
421                    this.equality = superior.getEquality();
422                    this.equalityOid = this.equality.getOid();
423                }
424            }
425        }
426    
427    
428        /**
429         * Build the ORDERING MR reference for an AttributeType
430         */
431        private void buildOrdering( List<Throwable> errors, Registries registries )
432        {
433            if ( orderingOid != null )
434            {
435                MatchingRule ordering = null;
436    
437                try
438                {
439                    ordering = registries.getMatchingRuleRegistry().lookup( orderingOid );
440                }
441                catch ( NamingException ne )
442                {
443                    // Not allowed.
444                    String msg = I18n.err( I18n.ERR_04310, orderingOid, getName() );
445    
446                    Throwable error = new LdapSchemaViolationException( msg, ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX );
447                    errors.add( error );
448                    LOG.info( msg );
449                    return;
450                }
451    
452                if ( ordering != null )
453                {
454                    this.ordering = ordering;
455                }
456                else
457                {
458                    // Not allowed.
459                    String msg = I18n.err( I18n.ERR_04311, orderingOid, getName() );
460    
461                    Throwable error = new LdapSchemaViolationException( msg, ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX );
462                    errors.add( error );
463                    LOG.info( msg );
464                }
465            }
466            else
467            {
468                // If the AT has a superior, take its Ordering MR if any
469                if ( ( superior != null ) && ( superior.getOrdering() != null ) )
470                {
471                    this.ordering = superior.getOrdering();
472                    this.orderingOid = this.ordering.getOid();
473                }
474            }
475        }
476    
477    
478        /**
479         * Build the SUBSTR MR reference for an AttributeType
480         */
481        private void buildSubstring( List<Throwable> errors, Registries registries )
482        {
483            // The Substring MR. It can be null
484            if ( substringOid != null )
485            {
486                MatchingRule substring = null;
487    
488                try
489                {
490                    substring = registries.getMatchingRuleRegistry().lookup( substringOid );
491                }
492                catch ( NamingException ne )
493                {
494                    // Not allowed.
495                    String msg = I18n.err( I18n.ERR_04312, substringOid, getName() );
496    
497                    Throwable error = new LdapSchemaViolationException( msg, ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX );
498                    errors.add( error );
499                    LOG.info( msg );
500                    return;
501                }
502    
503                if ( substring != null )
504                {
505                    this.substring = substring;
506                }
507                else
508                {
509                    // Not allowed.
510                    String msg = I18n.err( I18n.ERR_04313, substringOid, getName() );
511    
512                    Throwable error = new LdapSchemaViolationException( msg, ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX );
513                    errors.add( error );
514                    LOG.info( msg );
515                    return;
516                }
517            }
518            else
519            {
520                // If the AT has a superior, take its Substring MR if any
521                if ( ( superior != null ) && ( superior.getSubstring() != null ) )
522                {
523                    this.substring = superior.getSubstring();
524                    this.substringOid = this.substring.getOid();
525                }
526            }
527        }
528    
529    
530        /**
531         * Check the constraints for the Usage field.
532         */
533        private void checkUsage( List<Throwable> errors, Registries registries )
534        {
535            // Check that the AT usage is the same that its superior
536            if ( ( superior != null ) && ( usage != superior.getUsage() ) )
537            {
538                // This is an error
539                String msg = I18n.err( I18n.ERR_04314, getName() );
540    
541                Throwable error = new LdapSchemaViolationException( msg, ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX );
542                errors.add( error );
543                LOG.info( msg );
544                return;
545            }
546    
547            // Now, check that the AttributeType's USAGE does not conflict
548            if ( !isUserModifiable() && ( usage == UsageEnum.USER_APPLICATIONS ) )
549            {
550                // Cannot have a not user modifiable AT which is not an operational AT
551                String msg = I18n.err( I18n.ERR_04315, getName() );
552    
553                Throwable error = new LdapSchemaViolationException( msg, ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX );
554                errors.add( error );
555                LOG.info( msg );
556            }
557        }
558    
559    
560        /**
561         * Check the constraints for the Collective field.
562         */
563        private void checkCollective( List<Throwable> errors, Registries registries )
564        {
565            if ( superior != null )
566            {
567                if ( superior.isCollective() )
568                {
569                    // An AttributeType will be collective if its superior is collective
570                    this.isCollective = true;
571                }
572            }
573    
574            if ( isCollective() && ( usage != UsageEnum.USER_APPLICATIONS ) )
575            {
576                // An AttributeType which is collective must be a USER attributeType
577                String msg = I18n.err( I18n.ERR_04316, getName() );
578    
579                Throwable error = new LdapSchemaViolationException( msg, ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX );
580                errors.add( error );
581                LOG.info( msg );
582            }
583        }
584    
585    
586        /**
587         * Inject the attributeType into the registries, updating the references to
588         * other SchemaObject.
589         * 
590         * If one of the referenced SchemaObject does not exist (SUP, EQUALITY, ORDERING, SUBSTR, SYNTAX), 
591         * an exception is thrown.
592         *
593         * @param registries The Registries
594         * @exception If the AttributeType is not valid 
595         */
596        public void addToRegistries( List<Throwable> errors, Registries registries ) throws NamingException
597        {
598            if ( registries != null )
599            {
600                AttributeTypeRegistry attributeTypeRegistry = registries.getAttributeTypeRegistry();
601    
602                // The superior
603                if ( !buildSuperior( errors, registries ) )
604                {
605                    // We have had errors, let's stop here as we need a correct superior to continue
606                    return;
607                }
608    
609                // The Syntax
610                buildSyntax( errors, registries );
611    
612                // The EQUALITY matching rule
613                buildEquality( errors, registries );
614    
615                // The ORDERING matching rule
616                buildOrdering( errors, registries );
617    
618                // The SUBSTR matching rule
619                buildSubstring( errors, registries );
620    
621                // Check the USAGE
622                checkUsage( errors, registries );
623    
624                // Check the COLLECTIVE element
625                checkCollective( errors, registries );
626    
627                // Inject the attributeType into the oid/normalizer map
628                attributeTypeRegistry.addMappingFor( this );
629    
630                // Register this AttributeType into the Descendant map
631                attributeTypeRegistry.registerDescendants( this, superior );
632    
633                /**
634                 * Add the AT references (using and usedBy) : 
635                 * AT -> MR (for EQUALITY, ORDERING and SUBSTR)
636                 * AT -> S
637                 * AT -> AT
638                 */
639                if ( equality != null )
640                {
641                    registries.addReference( this, equality );
642                }
643    
644                if ( ordering != null )
645                {
646                    registries.addReference( this, ordering );
647                }
648    
649                if ( substring != null )
650                {
651                    registries.addReference( this, substring );
652                }
653    
654                if ( syntax != null )
655                {
656                    registries.addReference( this, syntax );
657                }
658    
659                if ( superior != null )
660                {
661                    registries.addReference( this, superior );
662                }
663            }
664        }
665    
666    
667        /**
668         * Remove the attributeType from the registries, updating the references to
669         * other SchemaObject.
670         * 
671         * If one of the referenced SchemaObject does not exist (SUP, EQUALITY, ORDERING, SUBSTR, SYNTAX), 
672         * an exception is thrown.
673         *
674         * @param registries The Registries
675         * @exception If the AttributeType is not valid 
676         */
677        public void removeFromRegistries( List<Throwable> errors, Registries registries ) throws NamingException
678        {
679            if ( registries != null )
680            {
681                AttributeTypeRegistry attributeTypeRegistry = registries.getAttributeTypeRegistry();
682    
683                // Remove the attributeType from the oid/normalizer map
684                attributeTypeRegistry.removeMappingFor( this );
685    
686                // Unregister this AttributeType into the Descendant map
687                attributeTypeRegistry.unregisterDescendants( this, superior );
688    
689                /**
690                 * Remove the AT references (using and usedBy) : 
691                 * AT -> MR (for EQUALITY, ORDERING and SUBSTR)
692                 * AT -> S
693                 * AT -> AT
694                 */
695                if ( equality != null )
696                {
697                    registries.delReference( this, equality );
698                }
699    
700                if ( ordering != null )
701                {
702                    registries.delReference( this, ordering );
703                }
704    
705                if ( substring != null )
706                {
707                    registries.delReference( this, substring );
708                }
709    
710                if ( syntax != null )
711                {
712                    registries.delReference( this, syntax );
713                }
714    
715                if ( superior != null )
716                {
717                    registries.delReference( this, superior );
718                }
719            }
720        }
721    
722    
723        /**
724         * Gets whether or not this AttributeType is single-valued.
725         * 
726         * @return true if only one value can exist for this AttributeType, false
727         *         otherwise
728         */
729        public boolean isSingleValued()
730        {
731            return isSingleValued;
732        }
733    
734    
735        /**
736         * Tells if this AttributeType is Single Valued or not
737         *
738         * @param singleValue True if the AttributeType is single-valued
739         */
740        public void setSingleValued( boolean singleValued )
741        {
742            if ( !isReadOnly )
743            {
744                this.isSingleValued = singleValued;
745            }
746        }
747    
748    
749        /**
750         * Gets whether or not this AttributeType can be modified by a user.
751         * 
752         * @return true if users can modify it, false if only the directory can.
753         */
754        public boolean isUserModifiable()
755        {
756            return canUserModify;
757        }
758    
759    
760        /**
761         * Tells if this AttributeType can be modified by a user or not
762         *
763         * @param canUserModify The flag to set
764         */
765        public void setUserModifiable( boolean canUserModify )
766        {
767            if ( !isReadOnly )
768            {
769                this.canUserModify = canUserModify;
770            }
771        }
772    
773    
774        /**
775         * Gets whether or not this AttributeType is a collective attribute.
776         * 
777         * @return true if the attribute is collective, false otherwise
778         */
779        public boolean isCollective()
780        {
781            return isCollective;
782        }
783    
784    
785        /**
786         * Updates the collective flag
787         *
788         * @param collective The new value to set
789         */
790        public void updateCollective( boolean collective )
791        {
792            this.isCollective = collective;
793        }
794    
795    
796        /**
797         * Sets the collective flag
798         *
799         * @param collective The new value to set
800         */
801        public void setCollective( boolean collective )
802        {
803            if ( !isReadOnly )
804            {
805                this.isCollective = collective;
806            }
807        }
808    
809    
810        /**
811         * Determines the usage for this AttributeType.
812         * 
813         * @return a type safe UsageEnum
814         */
815        public UsageEnum getUsage()
816        {
817            return usage;
818        }
819    
820    
821        /**
822         * Sets the AttributeType usage, one of :<br>
823         * <li>USER_APPLICATIONS
824         * <li>DIRECTORY_OPERATION
825         * <li>DISTRIBUTED_OPERATION
826         * <li>DSA_OPERATION
827         * <br>
828         * @see UsageEnum
829         * @param usage The AttributeType usage
830         */
831        public void setUsage( UsageEnum usage )
832        {
833            if ( !isReadOnly )
834            {
835                this.usage = usage;
836            }
837        }
838    
839    
840        /**
841         * Updates the AttributeType usage, one of :<br>
842         * <li>USER_APPLICATIONS
843         * <li>DIRECTORY_OPERATION
844         * <li>DISTRIBUTED_OPERATION
845         * <li>DSA_OPERATION
846         * <br>
847         * @see UsageEnum
848         * @param usage The AttributeType usage
849         */
850        public void updateUsage( UsageEnum usage )
851        {
852            this.usage = usage;
853        }
854    
855    
856        /**
857         * Gets a length limit for this AttributeType.
858         * 
859         * @return the length of the attribute
860         */
861        public int getSyntaxLength()
862        {
863            return syntaxLength;
864        }
865    
866    
867        /**
868         * Sets the length limit of this AttributeType based on its associated
869         * syntax.
870         * 
871         * @param length the new length to set
872         */
873        public void setSyntaxLength( int length )
874        {
875            if ( !isReadOnly )
876            {
877                this.syntaxLength = length;
878            }
879        }
880    
881    
882        /**
883         * Gets the the superior AttributeType of this AttributeType.
884         * 
885         * @return the superior AttributeType for this AttributeType
886         */
887        public AttributeType getSuperior()
888        {
889            return superior;
890        }
891    
892    
893        /**
894         * Gets the OID of the superior AttributeType for this AttributeType.
895         * 
896         * @return The OID of the superior AttributeType for this AttributeType.
897         */
898        public String getSuperiorOid()
899        {
900            return superiorOid;
901        }
902    
903    
904        /**
905         * Gets the Name of the superior AttributeType for this AttributeType.
906         * 
907         * @return The Name of the superior AttributeType for this AttributeType.
908         */
909        public String getSuperiorName()
910        {
911            if ( superior != null )
912            {
913                return superior.getName();
914            }
915            else
916            {
917                return superiorOid;
918            }
919        }
920    
921    
922        /**
923         * Sets the superior AttributeType OID of this AttributeType
924         *
925         * @param superiorOid The superior AttributeType OID of this AttributeType
926         */
927        public void setSuperiorOid( String superiorOid )
928        {
929            if ( !isReadOnly )
930            {
931                this.superiorOid = superiorOid;
932            }
933        }
934    
935    
936        /**
937         * Sets the superior for this AttributeType
938         *
939         * @param superior The superior for this AttributeType
940         */
941        public void setSuperior( AttributeType superior )
942        {
943            if ( !isReadOnly )
944            {
945                this.superior = superior;
946                this.superiorOid = superior.getOid();
947            }
948        }
949    
950    
951        /**
952         * Sets the superior oid for this AttributeType
953         *
954         * @param superior The superior oid for this AttributeType
955         */
956        public void setSuperior( String superiorOid )
957        {
958            if ( !isReadOnly )
959            {
960                this.superiorOid = superiorOid;
961            }
962        }
963    
964    
965        /**
966         * Update the associated Superior AttributeType, even if the SchemaObject is readOnly
967         *
968         * @param superior The superior for this AttributeType
969         */
970        public void updateSuperior( AttributeType superior )
971        {
972            this.superior = superior;
973            this.superiorOid = superior.getOid();
974        }
975    
976    
977        /**
978         * Gets the Syntax for this AttributeType's values.
979         * 
980         * @return the value syntax
981         */
982        public LdapSyntax getSyntax()
983        {
984            return syntax;
985        }
986    
987    
988        /**
989         * Gets the Syntax name for this AttributeType's values.
990         * 
991         * @return the value syntax name
992         */
993        public String getSyntaxName()
994        {
995            if ( syntax != null )
996            {
997                return syntax.getName();
998            }
999            else
1000            {
1001                return null;
1002            }
1003        }
1004    
1005    
1006        /**
1007         * Gets the Syntax OID for this AttributeType's values.
1008         * 
1009         * @return the value syntax's OID
1010         */
1011        public String getSyntaxOid()
1012        {
1013            return syntaxOid;
1014        }
1015    
1016    
1017        /**
1018         * Sets the Syntax OID for this AttributeType
1019         *
1020         * @param superiorOid The syntax OID for this AttributeType
1021         */
1022        public void setSyntaxOid( String syntaxOid )
1023        {
1024            if ( !isReadOnly )
1025            {
1026                this.syntaxOid = syntaxOid;
1027            }
1028        }
1029    
1030    
1031        /**
1032         * Sets the Syntax for this AttributeType
1033         *
1034         * @param syntax The Syntax for this AttributeType
1035         */
1036        public void setSyntax( LdapSyntax syntax )
1037        {
1038            if ( !isReadOnly )
1039            {
1040                this.syntax = syntax;
1041                this.syntaxOid = syntax.getOid();
1042            }
1043        }
1044    
1045    
1046        /**
1047         * Update the associated Syntax, even if the SchemaObject is readOnly
1048         *
1049         * @param syntax The Syntax for this AttributeType
1050         */
1051        public void updateSyntax( LdapSyntax syntax )
1052        {
1053            this.syntax = syntax;
1054            this.syntaxOid = syntax.getOid();
1055        }
1056    
1057    
1058        /**
1059         * Gets the MatchingRule for this AttributeType used for equality matching.
1060         * 
1061         * @return the equality matching rule
1062         */
1063        public MatchingRule getEquality()
1064        {
1065            return equality;
1066        }
1067    
1068    
1069        /**
1070         * Gets the Equality OID for this AttributeType's values.
1071         * 
1072         * @return the value Equality's OID
1073         */
1074        public String getEqualityOid()
1075        {
1076            return equalityOid;
1077        }
1078    
1079    
1080        /**
1081         * Gets the Equality Name for this AttributeType's values.
1082         * 
1083         * @return the value Equality's Name
1084         */
1085        public String getEqualityName()
1086        {
1087            if ( equality != null )
1088            {
1089                return equality.getName();
1090            }
1091            else
1092            {
1093                return equalityOid;
1094            }
1095        }
1096    
1097    
1098        /**
1099         * Sets the Equality OID for this AttributeType
1100         *
1101         * @param equalityOid The Equality OID for this AttributeType
1102         */
1103        public void setEqualityOid( String equalityOid )
1104        {
1105            if ( !isReadOnly )
1106            {
1107                this.equalityOid = equalityOid;
1108            }
1109        }
1110    
1111    
1112        /**
1113         * Sets the Equality MR for this AttributeType
1114         *
1115         * @param equality The Equality MR for this AttributeType
1116         */
1117        public void setEquality( MatchingRule equality )
1118        {
1119            if ( !isReadOnly )
1120            {
1121                this.equality = equality;
1122                this.equalityOid = equality.getOid();
1123            }
1124        }
1125    
1126    
1127        /**
1128         * Update the associated Equality MatchingRule, even if the SchemaObject is readOnly
1129         *
1130         * @param equality The Equality MR for this AttributeType
1131         */
1132        public void updateEquality( MatchingRule equality )
1133        {
1134            this.equality = equality;
1135            this.equalityOid = equality.getOid();
1136        }
1137    
1138    
1139        /**
1140         * Gets the MatchingRule for this AttributeType used for Ordering matching.
1141         * 
1142         * @return the Ordering matching rule
1143         */
1144        public MatchingRule getOrdering()
1145        {
1146            return ordering;
1147        }
1148    
1149    
1150        /**
1151         * Gets the MatchingRule name for this AttributeType used for Ordering matching.
1152         * 
1153         * @return the Ordering matching rule name
1154         */
1155        public String getOrderingName()
1156        {
1157            if ( ordering != null )
1158            {
1159                return ordering.getName();
1160            }
1161            else
1162            {
1163                return orderingOid;
1164            }
1165        }
1166    
1167    
1168        /**
1169         * Gets the Ordering OID for this AttributeType's values.
1170         * 
1171         * @return the value Equality's OID
1172         */
1173        public String getOrderingOid()
1174        {
1175            return orderingOid;
1176        }
1177    
1178    
1179        /**
1180         * Sets the Ordering OID for this AttributeType
1181         *
1182         * @param orderingOid The Ordering OID for this AttributeType
1183         */
1184        public void setOrderingOid( String orderingOid )
1185        {
1186            if ( !isReadOnly )
1187            {
1188                this.orderingOid = orderingOid;
1189            }
1190        }
1191    
1192    
1193        /**
1194         * Sets the Ordering MR for this AttributeType
1195         *
1196         * @param ordering The Ordering MR for this AttributeType
1197         */
1198        public void setOrdering( MatchingRule ordering )
1199        {
1200            if ( !isReadOnly )
1201            {
1202                this.ordering = ordering;
1203                this.orderingOid = ordering.getOid();
1204            }
1205        }
1206    
1207    
1208        /**
1209         * Update the associated Ordering MatchingRule, even if the SchemaObject is readOnly
1210         *
1211         * @param ordering The Ordering MR for this AttributeType
1212         */
1213        public void updateOrdering( MatchingRule ordering )
1214        {
1215            this.ordering = ordering;
1216            this.orderingOid = ordering.getOid();
1217        }
1218    
1219    
1220        /**
1221         * Gets the MatchingRule for this AttributeType used for Substr matching.
1222         * 
1223         * @return the Substr matching rule
1224         */
1225        public MatchingRule getSubstring()
1226        {
1227            return substring;
1228        }
1229    
1230    
1231        /**
1232         * Gets the MatchingRule name for this AttributeType used for Substring matching.
1233         * 
1234         * @return the Substring matching rule name
1235         */
1236        public String getSubstringName()
1237        {
1238            if ( substring != null )
1239            {
1240                return substring.getName();
1241            }
1242            else
1243            {
1244                return substringOid;
1245            }
1246        }
1247    
1248    
1249        /**
1250         * Gets the Substr OID for this AttributeType's values.
1251         * 
1252         * @return the value Substr's OID
1253         */
1254        public String getSubstringOid()
1255        {
1256            return substringOid;
1257        }
1258    
1259    
1260        /**
1261         * Sets the Substr OID for this AttributeType
1262         *
1263         * @param substrOid The Substr OID for this AttributeType
1264         */
1265        public void setSubstringOid( String substrOid )
1266        {
1267            if ( !isReadOnly )
1268            {
1269                this.substringOid = substrOid;
1270            }
1271        }
1272    
1273    
1274        /**
1275         * Sets the Substr MR for this AttributeType
1276         *
1277         * @param substring The Substr MR for this AttributeType
1278         */
1279        public void setSubstring( MatchingRule substring )
1280        {
1281            if ( !isReadOnly )
1282            {
1283                this.substring = substring;
1284                this.substringOid = substring.getOid();
1285            }
1286        }
1287    
1288    
1289        /**
1290         * Update the associated Substring MatchingRule, even if the SchemaObject is readOnly
1291         *
1292         * @param substring The Substr MR for this AttributeType
1293         */
1294        public void updateSubstring( MatchingRule substring )
1295        {
1296            this.substring = substring;
1297            this.substringOid = substring.getOid();
1298        }
1299    
1300    
1301        /**
1302         * Checks to see if this AttributeType is the ancestor of another
1303         * attributeType.
1304         *
1305         * @param descendant the perspective descendant to check
1306         * @return true if the descendant is truly a derived from this AttributeType
1307         */
1308        public boolean isAncestorOf( AttributeType descendant )
1309        {
1310            if ( ( descendant == null ) || this.equals( descendant ) )
1311            {
1312                return false;
1313            }
1314    
1315            return isAncestorOrEqual( this, descendant );
1316        }
1317    
1318    
1319        /**
1320         * Checks to see if this AttributeType is the descendant of another
1321         * attributeType.
1322         *
1323         * @param ancestor the perspective ancestor to check
1324         * @return true if this AttributeType truly descends from the ancestor
1325         */
1326        public boolean isDescendantOf( AttributeType ancestor )
1327        {
1328            if ( ( ancestor == null ) || equals( ancestor ) )
1329            {
1330                return false;
1331            }
1332    
1333            return isAncestorOrEqual( ancestor, this );
1334        }
1335    
1336    
1337        /**
1338         * Recursive method which checks to see if a descendant is really an ancestor or if the two
1339         * are equal.
1340         *
1341         * @param ancestor the possible ancestor of the descendant
1342         * @param descendant the possible descendant of the ancestor
1343         * @return true if the ancestor equals the descendant or if the descendant is really
1344         * a subtype of the ancestor. otherwise false
1345         */
1346        private boolean isAncestorOrEqual( AttributeType ancestor, AttributeType descendant )
1347        {
1348            if ( ( ancestor == null ) || ( descendant == null ) )
1349            {
1350                return false;
1351            }
1352    
1353            if ( ancestor.equals( descendant ) )
1354            {
1355                return true;
1356            }
1357    
1358            return isAncestorOrEqual( ancestor, descendant.getSuperior() );
1359        }
1360    
1361    
1362        /**
1363         * @see Object#toString()
1364         */
1365        public String toString()
1366        {
1367            return objectType + " " + DescriptionUtils.getDescription( this );
1368        }
1369    
1370    
1371        /**
1372         * Copy an AttributeType
1373         */
1374        public AttributeType copy()
1375        {
1376            AttributeType copy = new AttributeType( oid );
1377    
1378            // Copy the SchemaObject common data
1379            copy.copy( this );
1380    
1381            // Copy the canUserModify flag
1382            copy.canUserModify = canUserModify;
1383    
1384            // Copy the isCollective flag
1385            copy.isCollective = isCollective;
1386    
1387            // Copy the isSingleValue flag
1388            copy.isSingleValued = isSingleValued;
1389    
1390            // Copy the USAGE type
1391            copy.usage = usage;
1392    
1393            // All the references to other Registries object are set to null,
1394            // all the OIDs are copied
1395            // The EQUALITY MR
1396            copy.equality = null;
1397            copy.equalityOid = equalityOid;
1398    
1399            // The ORDERING MR
1400            copy.ordering = null;
1401            copy.orderingOid = orderingOid;
1402    
1403            // The SUBSTR MR
1404            copy.substring = null;
1405            copy.substringOid = substringOid;
1406    
1407            // The SUP AT
1408            copy.superior = null;
1409            copy.superiorOid = superiorOid;
1410    
1411            // The SYNTAX
1412            copy.syntax = null;
1413            copy.syntaxOid = syntaxOid;
1414            copy.syntaxLength = syntaxLength;
1415    
1416            return copy;
1417        }
1418    
1419    
1420        /**
1421         * {@inheritDoc}
1422         */
1423        public void clear()
1424        {
1425            // Clear the common elements
1426            super.clear();
1427    
1428            // Clear the references
1429            equality = null;
1430            ordering = null;
1431            substring = null;
1432            superior = null;
1433            syntax = null;
1434        }
1435    
1436    
1437        /**
1438         * @see Object#equals(Object)
1439         */
1440        public boolean equals( Object o )
1441        {
1442            if ( !super.equals( o ) )
1443            {
1444                return false;
1445            }
1446    
1447            if ( !( o instanceof AttributeType ) )
1448            {
1449                return false;
1450            }
1451    
1452            AttributeType that = ( AttributeType ) o;
1453    
1454            // The COLLECTIVE
1455            if ( isCollective != that.isCollective )
1456            {
1457                return false;
1458            }
1459    
1460            // The SINGLE_VALUE
1461            if ( isSingleValued != that.isSingleValued )
1462            {
1463                return false;
1464            }
1465    
1466            // The NO_USER_MODIFICATION
1467            if ( canUserModify != that.canUserModify )
1468            {
1469                return false;
1470            }
1471    
1472            // The USAGE
1473            if ( usage != that.usage )
1474            {
1475                return false;
1476            }
1477    
1478            // The equality
1479            if ( !compareOid( equalityOid, that.equalityOid ) )
1480            {
1481                return false;
1482            }
1483    
1484            if ( equality != null )
1485            {
1486                if ( !equality.equals( that.equality ) )
1487                {
1488                    return false;
1489                }
1490            }
1491            else
1492            {
1493                if ( that.equality != null )
1494                {
1495                    return false;
1496                }
1497            }
1498    
1499            // The ordering
1500            if ( !compareOid( orderingOid, that.orderingOid ) )
1501            {
1502                return false;
1503            }
1504    
1505            if ( ordering != null )
1506            {
1507                if ( !ordering.equals( that.ordering ) )
1508                {
1509                    return false;
1510                }
1511            }
1512            else
1513            {
1514                if ( that.ordering != null )
1515                {
1516                    return false;
1517                }
1518            }
1519    
1520            // The substring
1521            if ( !compareOid( substringOid, that.substringOid ) )
1522            {
1523                return false;
1524            }
1525    
1526            if ( substring != null )
1527            {
1528                if ( !substring.equals( that.substring ) )
1529                {
1530                    return false;
1531                }
1532            }
1533            else
1534            {
1535                if ( that.substring != null )
1536                {
1537                    return false;
1538                }
1539            }
1540    
1541            // The superior
1542            if ( !compareOid( superiorOid, that.superiorOid ) )
1543            {
1544                return false;
1545            }
1546    
1547            if ( superior != null )
1548            {
1549                if ( !superior.equals( that.superior ) )
1550                {
1551                    return false;
1552                }
1553            }
1554            else
1555            {
1556                if ( that.superior != null )
1557                {
1558                    return false;
1559                }
1560            }
1561    
1562            // The syntax
1563            if ( !compareOid( syntaxOid, that.syntaxOid ) )
1564            {
1565                return false;
1566            }
1567    
1568            if ( syntaxLength != that.syntaxLength )
1569            {
1570                return false;
1571            }
1572    
1573            if ( syntax == null )
1574            {
1575                return that.syntax == null;
1576            }
1577    
1578            if ( syntax.equals( that.syntax ) )
1579            {
1580                return syntaxLength == that.syntaxLength;
1581            }
1582            else
1583            {
1584                return false;
1585            }
1586        }
1587    }