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 "NAME" SP qdescrs ] ; short names (descriptors)
054 * [ SP "DESC" SP qdstring ] ; description
055 * [ SP "OBSOLETE" ] ; not active
056 * [ SP "SUP" SP oid ] ; supertype
057 * [ SP "EQUALITY" SP oid ] ; equality matching rule
058 * [ SP "ORDERING" SP oid ] ; ordering matching rule
059 * [ SP "SUBSTR" SP oid ] ; substrings matching rule
060 * [ SP "SYNTAX" SP noidlen ] ; value syntax
061 * [ SP "SINGLE-VALUE" ] ; single-value
062 * [ SP "COLLECTIVE" ] ; collective
063 * [ SP "NO-USER-MODIFICATION" ]; not user modifiable
064 * [ SP "USAGE" SP usage ] ; usage
065 * extensions WSP RPAREN ; extensions
066 *
067 * usage = "userApplications" / ; user
068 * "directoryOperation" / ; directory operational
069 * "distributedOperation" / ; DSA-shared operational
070 * "dSAOperation" ; 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, "1.3.6.4.1.1466.0{64}" 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 }