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 org.apache.directory.shared.i18n.I18n;
028 import org.apache.directory.shared.ldap.exception.LdapException;
029 import org.apache.directory.shared.ldap.exception.LdapProtocolErrorException;
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: 927122 $
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 LdapProtocolErrorException( msg );
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 ( LdapException 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 LdapProtocolErrorException( msg );
276 errors.add( error );
277 LOG.info( msg );
278 isOk = false;
279
280 break;
281 }
282 else
283 {
284 superiors.add( tmp.getOid() );
285 tmp = tmp.getSuperior();
286 }
287 }
288
289 superiors.clear();
290
291 return isOk;
292 }
293 else
294 {
295 // Not allowed.
296 String msg = I18n.err( I18n.ERR_04305, superiorOid, getName() );
297
298 Throwable error = new LdapSchemaViolationException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, msg );
299 errors.add( error );
300 LOG.info( msg );
301
302 // Get out now
303 return false;
304 }
305 }
306 else
307 {
308 // No superior, just return
309 return true;
310 }
311 }
312
313
314 /**
315 * Build the SYNTAX reference for an AttributeType
316 */
317 private void buildSyntax( List<Throwable> errors, Registries registries )
318 {
319 if ( syntaxOid != null )
320 {
321 LdapSyntax syntax = null;
322
323 try
324 {
325 syntax = registries.getLdapSyntaxRegistry().lookup( syntaxOid );
326 }
327 catch ( LdapException ne )
328 {
329 // Not allowed.
330 String msg = I18n.err( I18n.ERR_04306, syntaxOid, getName() );
331
332 Throwable error = new LdapProtocolErrorException( msg );
333 errors.add( error );
334 LOG.info( msg );
335 return;
336 }
337
338 if ( syntax != null )
339 {
340 // Update the Syntax reference
341 this.syntax = syntax;
342 }
343 else
344 {
345 // Not allowed.
346 String msg = I18n.err( I18n.ERR_04306, syntaxOid, getName() );
347
348 Throwable error = new LdapSchemaViolationException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, msg );
349 errors.add( error );
350 LOG.info( msg );
351 return;
352 }
353 }
354 else
355 {
356 // We inherit from the superior's syntax, if any
357 if ( superior != null )
358 {
359 this.syntax = superior.getSyntax();
360 this.syntaxOid = this.syntax.getOid();
361 }
362 else
363 {
364 // Not allowed.
365 String msg = I18n.err( I18n.ERR_04307, getName() );
366
367 Throwable error = new LdapProtocolErrorException( msg );
368 errors.add( error );
369 LOG.info( msg );
370 return;
371 }
372 }
373 }
374
375
376 /**
377 * Build the EQUALITY MR reference for an AttributeType
378 */
379 private void buildEquality( List<Throwable> errors, Registries registries )
380 {
381 // The equality MR. It can be null
382 if ( equalityOid != null )
383 {
384 MatchingRule equality = null;
385
386 try
387 {
388 equality = registries.getMatchingRuleRegistry().lookup( equalityOid );
389 }
390 catch ( LdapException ne )
391 {
392 // Not allowed.
393 String msg = I18n.err( I18n.ERR_04308, equalityOid, getName() );
394
395 Throwable error = new LdapProtocolErrorException( msg );
396 errors.add( error );
397 LOG.info( msg );
398 return;
399 }
400
401 if ( equality != null )
402 {
403 this.equality = equality;
404 }
405 else
406 {
407 // Not allowed.
408 String msg = I18n.err( I18n.ERR_04309, equalityOid, getName() );
409
410 Throwable error = new LdapSchemaViolationException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, msg );
411 errors.add( error );
412 LOG.info( msg );
413 }
414 }
415 else
416 {
417 // If the AT has a superior, take its Equality MR if any
418 if ( ( superior != null ) && ( superior.getEquality() != null ) )
419 {
420 this.equality = superior.getEquality();
421 this.equalityOid = this.equality.getOid();
422 }
423 }
424 }
425
426
427 /**
428 * Build the ORDERING MR reference for an AttributeType
429 */
430 private void buildOrdering( List<Throwable> errors, Registries registries )
431 {
432 if ( orderingOid != null )
433 {
434 MatchingRule ordering = null;
435
436 try
437 {
438 ordering = registries.getMatchingRuleRegistry().lookup( orderingOid );
439 }
440 catch ( LdapException ne )
441 {
442 // Not allowed.
443 String msg = I18n.err( I18n.ERR_04310, orderingOid, getName() );
444
445 Throwable error = new LdapProtocolErrorException( msg );
446 errors.add( error );
447 LOG.info( msg );
448 return;
449 }
450
451 if ( ordering != null )
452 {
453 this.ordering = ordering;
454 }
455 else
456 {
457 // Not allowed.
458 String msg = I18n.err( I18n.ERR_04311, orderingOid, getName() );
459
460 Throwable error = new LdapProtocolErrorException( msg );
461 errors.add( error );
462 LOG.info( msg );
463 }
464 }
465 else
466 {
467 // If the AT has a superior, take its Ordering MR if any
468 if ( ( superior != null ) && ( superior.getOrdering() != null ) )
469 {
470 this.ordering = superior.getOrdering();
471 this.orderingOid = this.ordering.getOid();
472 }
473 }
474 }
475
476
477 /**
478 * Build the SUBSTR MR reference for an AttributeType
479 */
480 private void buildSubstring( List<Throwable> errors, Registries registries )
481 {
482 // The Substring MR. It can be null
483 if ( substringOid != null )
484 {
485 MatchingRule substring = null;
486
487 try
488 {
489 substring = registries.getMatchingRuleRegistry().lookup( substringOid );
490 }
491 catch ( LdapException ne )
492 {
493 // Not allowed.
494 String msg = I18n.err( I18n.ERR_04312, substringOid, getName() );
495
496 Throwable error = new LdapProtocolErrorException( msg );
497 errors.add( error );
498 LOG.info( msg );
499 return;
500 }
501
502 if ( substring != null )
503 {
504 this.substring = substring;
505 }
506 else
507 {
508 // Not allowed.
509 String msg = I18n.err( I18n.ERR_04313, substringOid, getName() );
510
511 Throwable error = new LdapSchemaViolationException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, msg );
512 errors.add( error );
513 LOG.info( msg );
514 return;
515 }
516 }
517 else
518 {
519 // If the AT has a superior, take its Substring MR if any
520 if ( ( superior != null ) && ( superior.getSubstring() != null ) )
521 {
522 this.substring = superior.getSubstring();
523 this.substringOid = this.substring.getOid();
524 }
525 }
526 }
527
528
529 /**
530 * Check the constraints for the Usage field.
531 */
532 private void checkUsage( List<Throwable> errors, Registries registries )
533 {
534 // Check that the AT usage is the same that its superior
535 if ( ( superior != null ) && ( usage != superior.getUsage() ) )
536 {
537 // This is an error
538 String msg = I18n.err( I18n.ERR_04314, getName() );
539
540 Throwable error = new LdapProtocolErrorException( msg );
541 errors.add( error );
542 LOG.info( msg );
543 return;
544 }
545
546 // Now, check that the AttributeType's USAGE does not conflict
547 if ( !isUserModifiable() && ( usage == UsageEnum.USER_APPLICATIONS ) )
548 {
549 // Cannot have a not user modifiable AT which is not an operational AT
550 String msg = I18n.err( I18n.ERR_04315, getName() );
551
552 Throwable error = new LdapProtocolErrorException( msg );
553 errors.add( error );
554 LOG.info( msg );
555 }
556 }
557
558
559 /**
560 * Check the constraints for the Collective field.
561 */
562 private void checkCollective( List<Throwable> errors, Registries registries )
563 {
564 if ( superior != null )
565 {
566 if ( superior.isCollective() )
567 {
568 // An AttributeType will be collective if its superior is collective
569 this.isCollective = true;
570 }
571 }
572
573 if ( isCollective() && ( usage != UsageEnum.USER_APPLICATIONS ) )
574 {
575 // An AttributeType which is collective must be a USER attributeType
576 String msg = I18n.err( I18n.ERR_04316, getName() );
577
578 Throwable error = new LdapProtocolErrorException( msg );
579 errors.add( error );
580 LOG.info( msg );
581 }
582 }
583
584
585 /**
586 * Inject the attributeType into the registries, updating the references to
587 * other SchemaObject.
588 *
589 * If one of the referenced SchemaObject does not exist (SUP, EQUALITY, ORDERING, SUBSTR, SYNTAX),
590 * an exception is thrown.
591 *
592 * @param registries The Registries
593 * @exception If the AttributeType is not valid
594 */
595 public void addToRegistries( List<Throwable> errors, Registries registries ) throws LdapException
596 {
597 if ( registries != null )
598 {
599 AttributeTypeRegistry attributeTypeRegistry = registries.getAttributeTypeRegistry();
600
601 // The superior
602 if ( !buildSuperior( errors, registries ) )
603 {
604 // We have had errors, let's stop here as we need a correct superior to continue
605 return;
606 }
607
608 // The Syntax
609 buildSyntax( errors, registries );
610
611 // The EQUALITY matching rule
612 buildEquality( errors, registries );
613
614 // The ORDERING matching rule
615 buildOrdering( errors, registries );
616
617 // The SUBSTR matching rule
618 buildSubstring( errors, registries );
619
620 // Check the USAGE
621 checkUsage( errors, registries );
622
623 // Check the COLLECTIVE element
624 checkCollective( errors, registries );
625
626 // Inject the attributeType into the oid/normalizer map
627 attributeTypeRegistry.addMappingFor( this );
628
629 // Register this AttributeType into the Descendant map
630 attributeTypeRegistry.registerDescendants( this, superior );
631
632 /**
633 * Add the AT references (using and usedBy) :
634 * AT -> MR (for EQUALITY, ORDERING and SUBSTR)
635 * AT -> S
636 * AT -> AT
637 */
638 if ( equality != null )
639 {
640 registries.addReference( this, equality );
641 }
642
643 if ( ordering != null )
644 {
645 registries.addReference( this, ordering );
646 }
647
648 if ( substring != null )
649 {
650 registries.addReference( this, substring );
651 }
652
653 if ( syntax != null )
654 {
655 registries.addReference( this, syntax );
656 }
657
658 if ( superior != null )
659 {
660 registries.addReference( this, superior );
661 }
662 }
663 }
664
665
666 /**
667 * Remove the attributeType from the registries, updating the references to
668 * other SchemaObject.
669 *
670 * If one of the referenced SchemaObject does not exist (SUP, EQUALITY, ORDERING, SUBSTR, SYNTAX),
671 * an exception is thrown.
672 *
673 * @param registries The Registries
674 * @exception If the AttributeType is not valid
675 */
676 public void removeFromRegistries( List<Throwable> errors, Registries registries ) throws LdapException
677 {
678 if ( registries != null )
679 {
680 AttributeTypeRegistry attributeTypeRegistry = registries.getAttributeTypeRegistry();
681
682 // Remove the attributeType from the oid/normalizer map
683 attributeTypeRegistry.removeMappingFor( this );
684
685 // Unregister this AttributeType into the Descendant map
686 attributeTypeRegistry.unregisterDescendants( this, superior );
687
688 /**
689 * Remove the AT references (using and usedBy) :
690 * AT -> MR (for EQUALITY, ORDERING and SUBSTR)
691 * AT -> S
692 * AT -> AT
693 */
694 if ( equality != null )
695 {
696 registries.delReference( this, equality );
697 }
698
699 if ( ordering != null )
700 {
701 registries.delReference( this, ordering );
702 }
703
704 if ( substring != null )
705 {
706 registries.delReference( this, substring );
707 }
708
709 if ( syntax != null )
710 {
711 registries.delReference( this, syntax );
712 }
713
714 if ( superior != null )
715 {
716 registries.delReference( this, superior );
717 }
718 }
719 }
720
721
722 /**
723 * Gets whether or not this AttributeType is single-valued.
724 *
725 * @return true if only one value can exist for this AttributeType, false
726 * otherwise
727 */
728 public boolean isSingleValued()
729 {
730 return isSingleValued;
731 }
732
733
734 /**
735 * Tells if this AttributeType is Single Valued or not
736 *
737 * @param singleValue True if the AttributeType is single-valued
738 */
739 public void setSingleValued( boolean singleValued )
740 {
741 if ( locked )
742 {
743 throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
744 }
745
746 if ( !isReadOnly )
747 {
748 this.isSingleValued = singleValued;
749 }
750 }
751
752
753 /**
754 * Gets whether or not this AttributeType can be modified by a user.
755 *
756 * @return true if users can modify it, false if only the directory can.
757 */
758 public boolean isUserModifiable()
759 {
760 return canUserModify;
761 }
762
763
764 /**
765 * Tells if this AttributeType can be modified by a user or not
766 *
767 * @param canUserModify The flag to set
768 */
769 public void setUserModifiable( boolean canUserModify )
770 {
771 if ( locked )
772 {
773 throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
774 }
775
776 if ( !isReadOnly )
777 {
778 this.canUserModify = canUserModify;
779 }
780 }
781
782
783 /**
784 * Gets whether or not this AttributeType is a collective attribute.
785 *
786 * @return true if the attribute is collective, false otherwise
787 */
788 public boolean isCollective()
789 {
790 return isCollective;
791 }
792
793
794 /**
795 * Updates the collective flag
796 *
797 * @param collective The new value to set
798 */
799 public void updateCollective( boolean collective )
800 {
801 if ( locked )
802 {
803 throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
804 }
805
806 this.isCollective = collective;
807 }
808
809
810 /**
811 * Sets the collective flag
812 *
813 * @param collective The new value to set
814 */
815 public void setCollective( boolean collective )
816 {
817 if ( locked )
818 {
819 throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
820 }
821
822 if ( !isReadOnly )
823 {
824 this.isCollective = collective;
825 }
826 }
827
828
829 /**
830 * Determines the usage for this AttributeType.
831 *
832 * @return a type safe UsageEnum
833 */
834 public UsageEnum getUsage()
835 {
836 return usage;
837 }
838
839
840 /**
841 * Sets 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 setUsage( UsageEnum usage )
851 {
852 if ( locked )
853 {
854 throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
855 }
856
857 if ( !isReadOnly )
858 {
859 this.usage = usage;
860 }
861 }
862
863
864 /**
865 * Updates the AttributeType usage, one of :<br>
866 * <li>USER_APPLICATIONS
867 * <li>DIRECTORY_OPERATION
868 * <li>DISTRIBUTED_OPERATION
869 * <li>DSA_OPERATION
870 * <br>
871 * @see UsageEnum
872 * @param usage The AttributeType usage
873 */
874 public void updateUsage( UsageEnum usage )
875 {
876 if ( locked )
877 {
878 throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
879 }
880
881 this.usage = usage;
882 }
883
884
885 /**
886 * Gets a length limit for this AttributeType.
887 *
888 * @return the length of the attribute
889 */
890 public int getSyntaxLength()
891 {
892 return syntaxLength;
893 }
894
895
896 /**
897 * Sets the length limit of this AttributeType based on its associated
898 * syntax.
899 *
900 * @param length the new length to set
901 */
902 public void setSyntaxLength( int length )
903 {
904 if ( locked )
905 {
906 throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
907 }
908
909 if ( !isReadOnly )
910 {
911 this.syntaxLength = length;
912 }
913 }
914
915
916 /**
917 * Gets the the superior AttributeType of this AttributeType.
918 *
919 * @return the superior AttributeType for this AttributeType
920 */
921 public AttributeType getSuperior()
922 {
923 return superior;
924 }
925
926
927 /**
928 * Gets the OID of the superior AttributeType for this AttributeType.
929 *
930 * @return The OID of the superior AttributeType for this AttributeType.
931 */
932 public String getSuperiorOid()
933 {
934 return superiorOid;
935 }
936
937
938 /**
939 * Gets the Name of the superior AttributeType for this AttributeType.
940 *
941 * @return The Name of the superior AttributeType for this AttributeType.
942 */
943 public String getSuperiorName()
944 {
945 if ( superior != null )
946 {
947 return superior.getName();
948 }
949 else
950 {
951 return superiorOid;
952 }
953 }
954
955
956 /**
957 * Sets the superior AttributeType OID of this AttributeType
958 *
959 * @param superiorOid The superior AttributeType OID of this AttributeType
960 */
961 public void setSuperiorOid( String superiorOid )
962 {
963 if ( locked )
964 {
965 throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
966 }
967
968 if ( !isReadOnly )
969 {
970 this.superiorOid = superiorOid;
971 }
972 }
973
974
975 /**
976 * Sets the superior for this AttributeType
977 *
978 * @param superior The superior for this AttributeType
979 */
980 public void setSuperior( AttributeType superior )
981 {
982 if ( locked )
983 {
984 throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
985 }
986
987 if ( !isReadOnly )
988 {
989 this.superior = superior;
990 this.superiorOid = superior.getOid();
991 }
992 }
993
994
995 /**
996 * Sets the superior oid for this AttributeType
997 *
998 * @param superior The superior oid for this AttributeType
999 */
1000 public void setSuperior( String superiorOid )
1001 {
1002 if ( locked )
1003 {
1004 throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
1005 }
1006
1007 if ( !isReadOnly )
1008 {
1009 this.superiorOid = superiorOid;
1010 }
1011 }
1012
1013
1014 /**
1015 * Update the associated Superior AttributeType, even if the SchemaObject is readOnly
1016 *
1017 * @param superior The superior for this AttributeType
1018 */
1019 public void updateSuperior( AttributeType superior )
1020 {
1021 if ( locked )
1022 {
1023 throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
1024 }
1025
1026 this.superior = superior;
1027 this.superiorOid = superior.getOid();
1028 }
1029
1030
1031 /**
1032 * Gets the Syntax for this AttributeType's values.
1033 *
1034 * @return the value syntax
1035 */
1036 public LdapSyntax getSyntax()
1037 {
1038 return syntax;
1039 }
1040
1041
1042 /**
1043 * Gets the Syntax name for this AttributeType's values.
1044 *
1045 * @return the value syntax name
1046 */
1047 public String getSyntaxName()
1048 {
1049 if ( syntax != null )
1050 {
1051 return syntax.getName();
1052 }
1053 else
1054 {
1055 return null;
1056 }
1057 }
1058
1059
1060 /**
1061 * Gets the Syntax OID for this AttributeType's values.
1062 *
1063 * @return the value syntax's OID
1064 */
1065 public String getSyntaxOid()
1066 {
1067 return syntaxOid;
1068 }
1069
1070
1071 /**
1072 * Sets the Syntax OID for this AttributeType
1073 *
1074 * @param superiorOid The syntax OID for this AttributeType
1075 */
1076 public void setSyntaxOid( String syntaxOid )
1077 {
1078 if ( locked )
1079 {
1080 throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
1081 }
1082
1083 if ( !isReadOnly )
1084 {
1085 this.syntaxOid = syntaxOid;
1086 }
1087 }
1088
1089
1090 /**
1091 * Sets the Syntax for this AttributeType
1092 *
1093 * @param syntax The Syntax for this AttributeType
1094 */
1095 public void setSyntax( LdapSyntax syntax )
1096 {
1097 if ( locked )
1098 {
1099 throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
1100 }
1101
1102 if ( !isReadOnly )
1103 {
1104 this.syntax = syntax;
1105 this.syntaxOid = syntax.getOid();
1106 }
1107 }
1108
1109
1110 /**
1111 * Update the associated Syntax, even if the SchemaObject is readOnly
1112 *
1113 * @param syntax The Syntax for this AttributeType
1114 */
1115 public void updateSyntax( LdapSyntax syntax )
1116 {
1117 if ( locked )
1118 {
1119 throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
1120 }
1121
1122 this.syntax = syntax;
1123 this.syntaxOid = syntax.getOid();
1124 }
1125
1126
1127 /**
1128 * Gets the MatchingRule for this AttributeType used for equality matching.
1129 *
1130 * @return the equality matching rule
1131 */
1132 public MatchingRule getEquality()
1133 {
1134 return equality;
1135 }
1136
1137
1138 /**
1139 * Gets the Equality OID for this AttributeType's values.
1140 *
1141 * @return the value Equality's OID
1142 */
1143 public String getEqualityOid()
1144 {
1145 return equalityOid;
1146 }
1147
1148
1149 /**
1150 * Gets the Equality Name for this AttributeType's values.
1151 *
1152 * @return the value Equality's Name
1153 */
1154 public String getEqualityName()
1155 {
1156 if ( equality != null )
1157 {
1158 return equality.getName();
1159 }
1160 else
1161 {
1162 return equalityOid;
1163 }
1164 }
1165
1166
1167 /**
1168 * Sets the Equality OID for this AttributeType
1169 *
1170 * @param equalityOid The Equality OID for this AttributeType
1171 */
1172 public void setEqualityOid( String equalityOid )
1173 {
1174 if ( locked )
1175 {
1176 throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
1177 }
1178
1179 if ( !isReadOnly )
1180 {
1181 this.equalityOid = equalityOid;
1182 }
1183 }
1184
1185
1186 /**
1187 * Sets the Equality MR for this AttributeType
1188 *
1189 * @param equality The Equality MR for this AttributeType
1190 */
1191 public void setEquality( MatchingRule equality )
1192 {
1193 if ( locked )
1194 {
1195 throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
1196 }
1197
1198 if ( !isReadOnly )
1199 {
1200 this.equality = equality;
1201 this.equalityOid = equality.getOid();
1202 }
1203 }
1204
1205
1206 /**
1207 * Update the associated Equality MatchingRule, even if the SchemaObject is readOnly
1208 *
1209 * @param equality The Equality MR for this AttributeType
1210 */
1211 public void updateEquality( MatchingRule equality )
1212 {
1213 if ( locked )
1214 {
1215 throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
1216 }
1217
1218 this.equality = equality;
1219 this.equalityOid = equality.getOid();
1220 }
1221
1222
1223 /**
1224 * Gets the MatchingRule for this AttributeType used for Ordering matching.
1225 *
1226 * @return the Ordering matching rule
1227 */
1228 public MatchingRule getOrdering()
1229 {
1230 return ordering;
1231 }
1232
1233
1234 /**
1235 * Gets the MatchingRule name for this AttributeType used for Ordering matching.
1236 *
1237 * @return the Ordering matching rule name
1238 */
1239 public String getOrderingName()
1240 {
1241 if ( ordering != null )
1242 {
1243 return ordering.getName();
1244 }
1245 else
1246 {
1247 return orderingOid;
1248 }
1249 }
1250
1251
1252 /**
1253 * Gets the Ordering OID for this AttributeType's values.
1254 *
1255 * @return the value Equality's OID
1256 */
1257 public String getOrderingOid()
1258 {
1259 return orderingOid;
1260 }
1261
1262
1263 /**
1264 * Sets the Ordering OID for this AttributeType
1265 *
1266 * @param orderingOid The Ordering OID for this AttributeType
1267 */
1268 public void setOrderingOid( String orderingOid )
1269 {
1270 if ( locked )
1271 {
1272 throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
1273 }
1274
1275 if ( !isReadOnly )
1276 {
1277 this.orderingOid = orderingOid;
1278 }
1279 }
1280
1281
1282 /**
1283 * Sets the Ordering MR for this AttributeType
1284 *
1285 * @param ordering The Ordering MR for this AttributeType
1286 */
1287 public void setOrdering( MatchingRule ordering )
1288 {
1289 if ( locked )
1290 {
1291 throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
1292 }
1293
1294 if ( !isReadOnly )
1295 {
1296 this.ordering = ordering;
1297 this.orderingOid = ordering.getOid();
1298 }
1299 }
1300
1301
1302 /**
1303 * Update the associated Ordering MatchingRule, even if the SchemaObject is readOnly
1304 *
1305 * @param ordering The Ordering MR for this AttributeType
1306 */
1307 public void updateOrdering( MatchingRule ordering )
1308 {
1309 if ( locked )
1310 {
1311 throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
1312 }
1313
1314 this.ordering = ordering;
1315 this.orderingOid = ordering.getOid();
1316 }
1317
1318
1319 /**
1320 * Gets the MatchingRule for this AttributeType used for Substr matching.
1321 *
1322 * @return the Substr matching rule
1323 */
1324 public MatchingRule getSubstring()
1325 {
1326 return substring;
1327 }
1328
1329
1330 /**
1331 * Gets the MatchingRule name for this AttributeType used for Substring matching.
1332 *
1333 * @return the Substring matching rule name
1334 */
1335 public String getSubstringName()
1336 {
1337 if ( substring != null )
1338 {
1339 return substring.getName();
1340 }
1341 else
1342 {
1343 return substringOid;
1344 }
1345 }
1346
1347
1348 /**
1349 * Gets the Substr OID for this AttributeType's values.
1350 *
1351 * @return the value Substr's OID
1352 */
1353 public String getSubstringOid()
1354 {
1355 return substringOid;
1356 }
1357
1358
1359 /**
1360 * Sets the Substr OID for this AttributeType
1361 *
1362 * @param substrOid The Substr OID for this AttributeType
1363 */
1364 public void setSubstringOid( String substrOid )
1365 {
1366 if ( locked )
1367 {
1368 throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
1369 }
1370
1371 if ( !isReadOnly )
1372 {
1373 this.substringOid = substrOid;
1374 }
1375 }
1376
1377
1378 /**
1379 * Sets the Substr MR for this AttributeType
1380 *
1381 * @param substring The Substr MR for this AttributeType
1382 */
1383 public void setSubstring( MatchingRule substring )
1384 {
1385 if ( locked )
1386 {
1387 throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
1388 }
1389
1390 if ( !isReadOnly )
1391 {
1392 this.substring = substring;
1393 this.substringOid = substring.getOid();
1394 }
1395 }
1396
1397
1398 /**
1399 * Update the associated Substring MatchingRule, even if the SchemaObject is readOnly
1400 *
1401 * @param substring The Substr MR for this AttributeType
1402 */
1403 public void updateSubstring( MatchingRule substring )
1404 {
1405 if ( locked )
1406 {
1407 throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
1408 }
1409
1410 this.substring = substring;
1411 this.substringOid = substring.getOid();
1412 }
1413
1414
1415 /**
1416 * Checks to see if this AttributeType is the ancestor of another
1417 * attributeType.
1418 *
1419 * @param descendant the perspective descendant to check
1420 * @return true if the descendant is truly a derived from this AttributeType
1421 */
1422 public boolean isAncestorOf( AttributeType descendant )
1423 {
1424 if ( ( descendant == null ) || this.equals( descendant ) )
1425 {
1426 return false;
1427 }
1428
1429 return isAncestorOrEqual( this, descendant );
1430 }
1431
1432
1433 /**
1434 * Checks to see if this AttributeType is the descendant of another
1435 * attributeType.
1436 *
1437 * @param ancestor the perspective ancestor to check
1438 * @return true if this AttributeType truly descends from the ancestor
1439 */
1440 public boolean isDescendantOf( AttributeType ancestor )
1441 {
1442 if ( ( ancestor == null ) || equals( ancestor ) )
1443 {
1444 return false;
1445 }
1446
1447 return isAncestorOrEqual( ancestor, this );
1448 }
1449
1450
1451 /**
1452 * Recursive method which checks to see if a descendant is really an ancestor or if the two
1453 * are equal.
1454 *
1455 * @param ancestor the possible ancestor of the descendant
1456 * @param descendant the possible descendant of the ancestor
1457 * @return true if the ancestor equals the descendant or if the descendant is really
1458 * a subtype of the ancestor. otherwise false
1459 */
1460 private boolean isAncestorOrEqual( AttributeType ancestor, AttributeType descendant )
1461 {
1462 if ( ( ancestor == null ) || ( descendant == null ) )
1463 {
1464 return false;
1465 }
1466
1467 if ( ancestor.equals( descendant ) )
1468 {
1469 return true;
1470 }
1471
1472 return isAncestorOrEqual( ancestor, descendant.getSuperior() );
1473 }
1474
1475
1476 /**
1477 * @see Object#toString()
1478 */
1479 public String toString()
1480 {
1481 return objectType + " " + DescriptionUtils.getDescription( this );
1482 }
1483
1484
1485 /**
1486 * Copy an AttributeType
1487 */
1488 public AttributeType copy()
1489 {
1490 AttributeType copy = new AttributeType( oid );
1491
1492 // Copy the SchemaObject common data
1493 copy.copy( this );
1494
1495 // Copy the canUserModify flag
1496 copy.canUserModify = canUserModify;
1497
1498 // Copy the isCollective flag
1499 copy.isCollective = isCollective;
1500
1501 // Copy the isSingleValue flag
1502 copy.isSingleValued = isSingleValued;
1503
1504 // Copy the USAGE type
1505 copy.usage = usage;
1506
1507 // All the references to other Registries object are set to null,
1508 // all the OIDs are copied
1509 // The EQUALITY MR
1510 copy.equality = null;
1511 copy.equalityOid = equalityOid;
1512
1513 // The ORDERING MR
1514 copy.ordering = null;
1515 copy.orderingOid = orderingOid;
1516
1517 // The SUBSTR MR
1518 copy.substring = null;
1519 copy.substringOid = substringOid;
1520
1521 // The SUP AT
1522 copy.superior = null;
1523 copy.superiorOid = superiorOid;
1524
1525 // The SYNTAX
1526 copy.syntax = null;
1527 copy.syntaxOid = syntaxOid;
1528 copy.syntaxLength = syntaxLength;
1529
1530 return copy;
1531 }
1532
1533
1534 /**
1535 * {@inheritDoc}
1536 */
1537 public void clear()
1538 {
1539 // Clear the common elements
1540 super.clear();
1541
1542 // Clear the references
1543 equality = null;
1544 ordering = null;
1545 substring = null;
1546 superior = null;
1547 syntax = null;
1548 }
1549
1550
1551 /**
1552 * @see Object#equals(Object)
1553 */
1554 public boolean equals( Object o )
1555 {
1556 if ( !super.equals( o ) )
1557 {
1558 return false;
1559 }
1560
1561 if ( !( o instanceof AttributeType ) )
1562 {
1563 return false;
1564 }
1565
1566 AttributeType that = ( AttributeType ) o;
1567
1568 // The COLLECTIVE
1569 if ( isCollective != that.isCollective )
1570 {
1571 return false;
1572 }
1573
1574 // The SINGLE_VALUE
1575 if ( isSingleValued != that.isSingleValued )
1576 {
1577 return false;
1578 }
1579
1580 // The NO_USER_MODIFICATION
1581 if ( canUserModify != that.canUserModify )
1582 {
1583 return false;
1584 }
1585
1586 // The USAGE
1587 if ( usage != that.usage )
1588 {
1589 return false;
1590 }
1591
1592 // The equality
1593 if ( !compareOid( equalityOid, that.equalityOid ) )
1594 {
1595 return false;
1596 }
1597
1598 if ( equality != null )
1599 {
1600 if ( !equality.equals( that.equality ) )
1601 {
1602 return false;
1603 }
1604 }
1605 else
1606 {
1607 if ( that.equality != null )
1608 {
1609 return false;
1610 }
1611 }
1612
1613 // The ordering
1614 if ( !compareOid( orderingOid, that.orderingOid ) )
1615 {
1616 return false;
1617 }
1618
1619 if ( ordering != null )
1620 {
1621 if ( !ordering.equals( that.ordering ) )
1622 {
1623 return false;
1624 }
1625 }
1626 else
1627 {
1628 if ( that.ordering != null )
1629 {
1630 return false;
1631 }
1632 }
1633
1634 // The substring
1635 if ( !compareOid( substringOid, that.substringOid ) )
1636 {
1637 return false;
1638 }
1639
1640 if ( substring != null )
1641 {
1642 if ( !substring.equals( that.substring ) )
1643 {
1644 return false;
1645 }
1646 }
1647 else
1648 {
1649 if ( that.substring != null )
1650 {
1651 return false;
1652 }
1653 }
1654
1655 // The superior
1656 if ( !compareOid( superiorOid, that.superiorOid ) )
1657 {
1658 return false;
1659 }
1660
1661 if ( superior != null )
1662 {
1663 if ( !superior.equals( that.superior ) )
1664 {
1665 return false;
1666 }
1667 }
1668 else
1669 {
1670 if ( that.superior != null )
1671 {
1672 return false;
1673 }
1674 }
1675
1676 // The syntax
1677 if ( !compareOid( syntaxOid, that.syntaxOid ) )
1678 {
1679 return false;
1680 }
1681
1682 if ( syntaxLength != that.syntaxLength )
1683 {
1684 return false;
1685 }
1686
1687 if ( syntax == null )
1688 {
1689 return that.syntax == null;
1690 }
1691
1692 if ( syntax.equals( that.syntax ) )
1693 {
1694 return syntaxLength == that.syntaxLength;
1695 }
1696 else
1697 {
1698 return false;
1699 }
1700 }
1701 }