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 }