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