001 /* 002 * CDDL HEADER START 003 * 004 * The contents of this file are subject to the terms of the 005 * Common Development and Distribution License, Version 1.0 only 006 * (the "License"). You may not use this file except in compliance 007 * with the License. 008 * 009 * You can obtain a copy of the license at 010 * trunk/opends/resource/legal-notices/OpenDS.LICENSE 011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE. 012 * See the License for the specific language governing permissions 013 * and limitations under the License. 014 * 015 * When distributing Covered Code, include this CDDL HEADER in each 016 * file and include the License file at 017 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, 018 * add the following below this CDDL HEADER, with the fields enclosed 019 * by brackets "[]" replaced with your own identifying information: 020 * Portions Copyright [yyyy] [name of copyright owner] 021 * 022 * CDDL HEADER END 023 * 024 * 025 * Copyright 2006-2008 Sun Microsystems, Inc. 026 */ 027 package org.opends.server.types; 028 import org.opends.messages.Message; 029 030 031 032 import java.util.Collection; 033 import java.util.List; 034 import java.util.Map; 035 036 import org.opends.server.api.ApproximateMatchingRule; 037 import org.opends.server.api.AttributeSyntax; 038 import org.opends.server.api.EqualityMatchingRule; 039 import org.opends.server.api.OrderingMatchingRule; 040 import org.opends.server.api.SubstringMatchingRule; 041 import org.opends.server.core.DirectoryServer; 042 import org.opends.server.schema.AttributeTypeSyntax; 043 044 import static org.opends.server.loggers.debug.DebugLogger.*; 045 import org.opends.server.loggers.debug.DebugTracer; 046 import static org.opends.messages.CoreMessages.*; 047 import static org.opends.server.util.ServerConstants.*; 048 import static org.opends.server.util.Validator.*; 049 050 051 052 /** 053 * This class defines a data structure for storing and interacting 054 * with an attribute type, which contains information about the format 055 * of an attribute and the syntax and matching rules that should be 056 * used when interacting with it. 057 * <p> 058 * Any methods which accesses the set of names associated with this 059 * attribute type, will retrieve the primary name as the first name, 060 * regardless of whether or not it was contained in the original set 061 * of <code>names</code> passed to the constructor. 062 * <p> 063 * Where ordered sets of names, or extra properties are provided, the 064 * ordering will be preserved when the associated fields are accessed 065 * via their getters or via the {@link #toString()} methods. 066 */ 067 @org.opends.server.types.PublicAPI( 068 stability=org.opends.server.types.StabilityLevel.UNCOMMITTED, 069 mayInstantiate=false, 070 mayExtend=false, 071 mayInvoke=true) 072 public final class AttributeType 073 extends CommonSchemaElements 074 implements SchemaFileElement 075 { 076 /** 077 * The tracer object for the debug logger. 078 */ 079 private static final DebugTracer TRACER = getTracer(); 080 081 // The approximate matching rule for this attribute type. 082 private final ApproximateMatchingRule approximateMatchingRule; 083 084 // The syntax for this attribute type. 085 private final AttributeSyntax syntax; 086 087 // The superior attribute type from which this attribute type 088 // inherits. 089 private final AttributeType superiorType; 090 091 // The attribute usage for this attribute type. 092 private final AttributeUsage attributeUsage; 093 094 // Indicates whether this attribute type is declared "collective". 095 private final boolean isCollective; 096 097 // Indicates whether this attribute type is declared 098 // "no-user-modification". 099 private final boolean isNoUserModification; 100 101 // Indicates whether this attribute type is the objectclass type. 102 private final boolean isObjectClassType; 103 104 // Indicates whether this attribute type is operational. 105 private final boolean isOperational; 106 107 // Indicates whether this attribute type is declared "single-value". 108 private final boolean isSingleValue; 109 110 // Indicates whether there is a possibility that this attribute type 111 // may have one or more subtypes that list this type or one of its 112 // subtypes as a superior. Note that this variable is intentional 113 // not declared "final", but if it ever gets set to "true", then it 114 // should never be unset back to "false". 115 private boolean mayHaveSubordinateTypes; 116 117 // The equality matching rule for this attribute type. 118 private final EqualityMatchingRule equalityMatchingRule; 119 120 // The ordering matching rule for this attribute type. 121 private final OrderingMatchingRule orderingMatchingRule; 122 123 // The definition string used to create this attribute type. 124 private final String definition; 125 126 // The OID for the associated syntax. 127 private final String syntaxOID; 128 129 // The substring matching rule for this attribute type. 130 private final SubstringMatchingRule substringMatchingRule; 131 132 133 134 /** 135 * Creates a new attribute type with the provided information. 136 * <p> 137 * If no <code>primaryName</code> is specified, but a set of 138 * <code>names</code> is specified, then the first name retrieved 139 * from the set of <code>names</code> will be used as the primary 140 * name. 141 * 142 * @param definition 143 * The definition string used to create this attribute 144 * type. It must not be {@code null}. 145 * @param primaryName 146 * The primary name for this attribute type, or 147 * <code>null</code> if there is no primary name. 148 * @param typeNames 149 * The full set of names for this attribute type, or 150 * <code>null</code> if there are no names. 151 * @param oid 152 * The OID for this attribute type. It must not be 153 * {@code null}. 154 * @param description 155 * The description for the attribute type, or 156 * <code>null</code> if there is no description. 157 * @param superiorType 158 * The reference to the superior type for this attribute 159 * type, or <code>null</code> if there is no superior 160 * type. 161 * @param syntax 162 * The syntax for this attribute type, or <code>null</code> 163 * if there is no syntax. 164 * @param attributeUsage 165 * The attribute usage for this attribute type, or 166 * <code>null</code> to default to user applications. 167 * @param isCollective 168 * Indicates whether this attribute type is declared 169 * "collective". 170 * @param isNoUserModification 171 * Indicates whether this attribute type is declared 172 * "no-user-modification". 173 * @param isObsolete 174 * Indicates whether this attribute type is declared 175 * "obsolete". 176 * @param isSingleValue 177 * Indicates whether this attribute type is declared 178 * "single-value". 179 */ 180 public AttributeType(String definition, String primaryName, 181 Collection<String> typeNames, 182 String oid, String description, 183 AttributeType superiorType, 184 AttributeSyntax syntax, 185 AttributeUsage attributeUsage, 186 boolean isCollective, 187 boolean isNoUserModification, 188 boolean isObsolete, boolean isSingleValue) 189 { 190 this(definition, primaryName, typeNames, oid, description, 191 superiorType, syntax, null, null, null, 192 null, attributeUsage, isCollective, 193 isNoUserModification, isObsolete, isSingleValue, null); 194 } 195 196 197 198 /** 199 * Creates a new attribute type with the provided information. 200 * <p> 201 * If no <code>primaryName</code> is specified, but a set of 202 * <code>names</code> is specified, then the first name retrieved 203 * from the set of <code>names</code> will be used as the primary 204 * name. 205 * 206 * @param definition 207 * The definition string used to create this attribute 208 * type. It must not be {@code null}. 209 * @param primaryName 210 * The primary name for this attribute type, or 211 * <code>null</code> if there is no primary name. 212 * @param typeNames 213 * The full set of names for this attribute type, or 214 * <code>null</code> if there are no names. 215 * @param oid 216 * The OID for this attribute type. It must not be 217 * {@code null}. 218 * @param description 219 * The description for the attribute type, or 220 * <code>null</code> if there is no description. 221 * @param superiorType 222 * The reference to the superior type for this attribute 223 * type, or <code>null</code> if there is no superior 224 * type. 225 * @param syntax 226 * The syntax for this attribute type, or <code>null</code> 227 * if there is no syntax. 228 * @param approximateMatchingRule 229 * The approximate matching rule for this attribute type, 230 * or <code>null</code> if there is no rule. 231 * @param equalityMatchingRule 232 * The equality matching rule for this attribute type, or 233 * <code>null</code> if there is no rule. 234 * @param orderingMatchingRule 235 * The ordering matching rule for this attribute type, or 236 * <code>null</code> if there is no rule. 237 * @param substringMatchingRule 238 * The substring matching rule for this attribute type, or 239 * <code>null</code> if there is no rule. 240 * @param attributeUsage 241 * The attribute usage for this attribute type, or 242 * <code>null</code> to default to user applications. 243 * @param isCollective 244 * Indicates whether this attribute type is declared 245 * "collective". 246 * @param isNoUserModification 247 * Indicates whether this attribute type is declared 248 * "no-user-modification". 249 * @param isObsolete 250 * Indicates whether this attribute type is declared 251 * "obsolete". 252 * @param isSingleValue 253 * Indicates whether this attribute type is declared 254 * "single-value". 255 * @param extraProperties 256 * A set of extra properties for this attribute type, or 257 * <code>null</code> if there are no extra properties. 258 */ 259 public AttributeType(String definition, String primaryName, 260 Collection<String> typeNames, 261 String oid, String description, 262 AttributeType superiorType, 263 AttributeSyntax syntax, 264 ApproximateMatchingRule 265 approximateMatchingRule, 266 EqualityMatchingRule equalityMatchingRule, 267 OrderingMatchingRule orderingMatchingRule, 268 SubstringMatchingRule substringMatchingRule, 269 AttributeUsage attributeUsage, 270 boolean isCollective, 271 boolean isNoUserModification, 272 boolean isObsolete, boolean isSingleValue, 273 Map<String,List<String>> extraProperties) 274 { 275 super(primaryName, typeNames, oid, description, isObsolete, 276 extraProperties); 277 278 279 ensureNotNull(definition, oid); 280 281 this.superiorType = superiorType; 282 this.isCollective = isCollective; 283 this.isNoUserModification = isNoUserModification; 284 this.isSingleValue = isSingleValue; 285 286 mayHaveSubordinateTypes = false; 287 288 int schemaFilePos = definition.indexOf(SCHEMA_PROPERTY_FILENAME); 289 if (schemaFilePos > 0) 290 { 291 String defStr; 292 try 293 { 294 int firstQuotePos = definition.indexOf('\'', schemaFilePos); 295 int secondQuotePos = definition.indexOf('\'', 296 firstQuotePos+1); 297 298 defStr = definition.substring(0, schemaFilePos).trim() + " " + 299 definition.substring(secondQuotePos+1).trim(); 300 } 301 catch (Exception e) 302 { 303 if (debugEnabled()) 304 { 305 TRACER.debugCaught(DebugLogLevel.ERROR, e); 306 } 307 308 defStr = definition; 309 } 310 311 this.definition = defStr; 312 } 313 else 314 { 315 this.definition = definition; 316 } 317 318 if (syntax == null) 319 { 320 if (superiorType != null) 321 { 322 this.syntax = superiorType.getSyntax(); 323 } 324 else 325 { 326 this.syntax = DirectoryServer.getDefaultAttributeSyntax(); 327 } 328 } 329 else 330 { 331 this.syntax = syntax; 332 } 333 syntaxOID = this.syntax.getOID(); 334 335 336 if (approximateMatchingRule == null) 337 { 338 this.approximateMatchingRule = 339 this.syntax.getApproximateMatchingRule(); 340 } 341 else 342 { 343 this.approximateMatchingRule = approximateMatchingRule; 344 } 345 346 347 if (equalityMatchingRule == null) 348 { 349 this.equalityMatchingRule = 350 this.syntax.getEqualityMatchingRule(); 351 } 352 else 353 { 354 this.equalityMatchingRule = equalityMatchingRule; 355 } 356 357 358 if (orderingMatchingRule == null) 359 { 360 this.orderingMatchingRule = 361 this.syntax.getOrderingMatchingRule(); 362 } 363 else 364 { 365 this.orderingMatchingRule = orderingMatchingRule; 366 } 367 368 369 if (substringMatchingRule == null) 370 { 371 this.substringMatchingRule = 372 this.syntax.getSubstringMatchingRule(); 373 } 374 else 375 { 376 this.substringMatchingRule = substringMatchingRule; 377 } 378 379 if (attributeUsage != null) 380 { 381 this.attributeUsage = attributeUsage; 382 } 383 else 384 { 385 this.attributeUsage = AttributeUsage.USER_APPLICATIONS; 386 } 387 388 if (oid.equals(OBJECTCLASS_ATTRIBUTE_TYPE_OID)) 389 { 390 isObjectClassType = true; 391 } 392 else 393 { 394 isObjectClassType = hasName(OBJECTCLASS_ATTRIBUTE_TYPE_NAME); 395 } 396 397 isOperational = this.attributeUsage.isOperational(); 398 } 399 400 401 402 /** 403 * Retrieves the definition string used to create this attribute 404 * type. 405 * 406 * @return The definition string used to create this attribute 407 * type. 408 */ 409 public String getDefinition() 410 { 411 return definition; 412 } 413 414 /** 415 * Retrieves the definition string used to create this attribute 416 * type and including the X-SCHEMA-FILE extension. 417 * 418 * @return The definition string used to create this attribute 419 * type including the X-SCHEMA-FILE extension. 420 */ 421 public String getDefinitionWithFileName() 422 { 423 if (getSchemaFile() != null) 424 { 425 int pos = definition.lastIndexOf(')'); 426 String defStr = definition.substring(0, pos).trim() + " " + 427 SCHEMA_PROPERTY_FILENAME + " '" + 428 getSchemaFile() + "' )"; 429 return defStr; 430 } 431 else 432 return definition; 433 } 434 435 /** 436 * Creates a new instance of this attribute type based on the 437 * definition string. It will also preserve other state information 438 * associated with this attribute type that is not included in the 439 * definition string (e.g., the name of the schema file with which 440 * it is associated). 441 * 442 * @return The new instance of this attribute type based on the 443 * definition string. 444 * 445 * @throws DirectoryException If a problem occurs while attempting 446 * to create a new attribute type 447 * instance from the definition string. 448 */ 449 public AttributeType recreateFromDefinition() 450 throws DirectoryException 451 { 452 ByteString value = ByteStringFactory.create(definition); 453 Schema schema = DirectoryServer.getSchema(); 454 455 AttributeType at = 456 AttributeTypeSyntax.decodeAttributeType(value, schema, 457 false); 458 at.setSchemaFile(getSchemaFile()); 459 at.mayHaveSubordinateTypes = mayHaveSubordinateTypes; 460 461 return at; 462 } 463 464 465 466 /** 467 * Retrieves the superior type for this attribute type. 468 * 469 * @return The superior type for this attribute type, or 470 * <CODE>null</CODE> if it does not have one. 471 */ 472 public AttributeType getSuperiorType() 473 { 474 return superiorType; 475 } 476 477 478 479 /** 480 * Indicates whether there is a possibility that this attribute type 481 * may have one or more subordinate attribute types defined in the 482 * server schema. This is only intended for use by the 483 * {@code org.opends.server.types.Entry} class for the purpose of 484 * determining whether to check for subtypes when retrieving 485 * attributes. Note that it is possible for this method to report 486 * false positives (if an attribute type that previously had one or 487 * more subordinate types no longer has any), but not false 488 * negatives. 489 * 490 * @return {@code true} if the {@code hasSubordinateTypes} flag has 491 * been set for this attribute type at any time since 492 * startup, or {@code false} if not. 493 */ 494 boolean mayHaveSubordinateTypes() 495 { 496 return mayHaveSubordinateTypes; 497 } 498 499 500 501 /** 502 * Sets a flag indicating that this attribute type may have one or 503 * more subordinate attribute types defined in the server schema. 504 * This is only intended for use by the 505 * {@code org.opends.server.types.Schema} class. 506 */ 507 void setMayHaveSubordinateTypes() 508 { 509 mayHaveSubordinateTypes = true; 510 } 511 512 513 514 /** 515 * Retrieves the syntax for this attribute type. 516 * 517 * @return The syntax for this attribute type. 518 */ 519 public AttributeSyntax getSyntax() 520 { 521 return syntax; 522 } 523 524 525 526 /** 527 * Retrieves the OID for this syntax associated with this attribute 528 * type. 529 * 530 * @return The OID for this syntax associated with this attribute 531 * type. 532 */ 533 public String getSyntaxOID() 534 { 535 return syntaxOID; 536 } 537 538 539 540 /** 541 * Retrieves the matching rule that should be used for approximate 542 * matching with this attribute type. 543 * 544 * @return The matching rule that should be used for approximate 545 * matching with this attribute type. 546 */ 547 public ApproximateMatchingRule getApproximateMatchingRule() 548 { 549 return approximateMatchingRule; 550 } 551 552 553 554 /** 555 * Retrieves the matching rule that should be used for equality 556 * matching with this attribute type. 557 * 558 * @return The matching rule that should be used for equality 559 * matching with this attribute type. 560 */ 561 public EqualityMatchingRule getEqualityMatchingRule() 562 { 563 return equalityMatchingRule; 564 } 565 566 567 568 /** 569 * Retrieves the matching rule that should be used for ordering with 570 * this attribute type. 571 * 572 * @return The matching rule that should be used for ordering with 573 * this attribute type. 574 */ 575 public OrderingMatchingRule getOrderingMatchingRule() 576 { 577 return orderingMatchingRule; 578 } 579 580 581 582 /** 583 * Retrieves the matching rule that should be used for substring 584 * matching with this attribute type. 585 * 586 * @return The matching rule that should be used for substring 587 * matching with this attribute type. 588 */ 589 public SubstringMatchingRule getSubstringMatchingRule() 590 { 591 return substringMatchingRule; 592 } 593 594 595 596 /** 597 * Retrieves the usage indicator for this attribute type. 598 * 599 * @return The usage indicator for this attribute type. 600 */ 601 public AttributeUsage getUsage() 602 { 603 return attributeUsage; 604 } 605 606 607 608 /** 609 * Indicates whether this is an operational attribute. An 610 * operational attribute is one with a usage of 611 * "directoryOperation", "distributedOperation", or "dSAOperation" 612 * (i.e., only userApplications is not operational). 613 * 614 * @return <CODE>true</CODE> if this is an operational attribute, 615 * or <CODE>false</CODE> if not. 616 */ 617 public boolean isOperational() 618 { 619 return isOperational; 620 } 621 622 623 624 /** 625 * Indicates whether this attribute type is declared "collective". 626 * 627 * @return <CODE>true</CODE> if this attribute type is declared 628 * "collective", or <CODE>false</CODE> if not. 629 */ 630 public boolean isCollective() 631 { 632 return isCollective; 633 } 634 635 636 637 /** 638 * Indicates whether this attribute type is declared 639 * "no-user-modification". 640 * 641 * @return <CODE>true</CODE> if this attribute type is declared 642 * "no-user-modification", or <CODE>false</CODE> if not. 643 */ 644 public boolean isNoUserModification() 645 { 646 return isNoUserModification; 647 } 648 649 650 651 /** 652 * Indicates whether this attribute type is declared "single-value". 653 * 654 * @return <CODE>true</CODE> if this attribute type is declared 655 * "single-value", or <CODE>false</CODE> if not. 656 */ 657 public boolean isSingleValue() 658 { 659 return isSingleValue; 660 } 661 662 663 664 /** 665 * Indicates whether this attribute type represents the 666 * "objectclass" attribute. The determination will be made based on 667 * the name and/or OID. 668 * 669 * @return <CODE>true</CODE> if this attribute type is the 670 * objectclass type, or <CODE>false</CODE> if not. 671 */ 672 public boolean isObjectClassType() 673 { 674 return isObjectClassType; 675 } 676 677 678 679 /** 680 * Attempts to normalize the provided value using the equality 681 * matching rule associated with this attribute type. 682 * 683 * @param value The value to be normalized. 684 * 685 * @return The normalized form of the provided value. 686 * 687 * @throws DirectoryException If this attribute type does not have 688 * an equality matching rule, or if the 689 * provided value could not be 690 * normalized. 691 */ 692 public ByteString normalize(ByteString value) 693 throws DirectoryException 694 { 695 if (equalityMatchingRule == null) 696 { 697 Message message = ERR_ATTR_TYPE_NORMALIZE_NO_MR.get( 698 String.valueOf(value), getNameOrOID()); 699 throw new DirectoryException(ResultCode.INAPPROPRIATE_MATCHING, 700 message); 701 } 702 703 return equalityMatchingRule.normalizeValue(value); 704 } 705 706 707 708 /** 709 * Generates a hash code for the specified attribute value. If an 710 * equality matching rule is defined for this type, then it will be 711 * used to generate the hash code. If the value does not have an 712 * equality matching rule but does have a normalized form, then that 713 * will be used to obtain the hash code. Otherwise, it will simply 714 * be the hash code of the provided value. 715 * 716 * @param value The attribute value for which to generate the hash 717 * code. 718 * 719 * @return The generated hash code for the provided value. 720 */ 721 public int generateHashCode(AttributeValue value) 722 { 723 try 724 { 725 if (equalityMatchingRule == null) 726 { 727 ByteString normalizedValue = value.getNormalizedValue(); 728 if (normalizedValue == null) 729 { 730 return value.getValue().hashCode(); 731 } 732 else 733 { 734 return normalizedValue.hashCode(); 735 } 736 } 737 else 738 { 739 return equalityMatchingRule.generateHashCode(value); 740 } 741 } 742 catch (Exception e) 743 { 744 if (debugEnabled()) 745 { 746 TRACER.debugCaught(DebugLogLevel.ERROR, e); 747 } 748 749 try 750 { 751 return value.getValue().hashCode(); 752 } 753 catch (Exception e2) 754 { 755 if (debugEnabled()) 756 { 757 TRACER.debugCaught(DebugLogLevel.ERROR, e2); 758 } 759 760 return 0; 761 } 762 } 763 } 764 765 766 767 /** 768 * Appends a string representation of this schema definition's 769 * non-generic properties to the provided buffer. 770 * 771 * @param buffer The buffer to which the information should be 772 * appended. 773 */ 774 protected void toStringContent(StringBuilder buffer) 775 { 776 if (superiorType != null) 777 { 778 buffer.append(" SUP "); 779 buffer.append(superiorType.getNameOrOID()); 780 } 781 782 if (equalityMatchingRule != null) 783 { 784 buffer.append(" EQUALITY "); 785 buffer.append(equalityMatchingRule.getNameOrOID()); 786 } 787 788 if (orderingMatchingRule != null) 789 { 790 buffer.append(" ORDERING "); 791 buffer.append(orderingMatchingRule.getNameOrOID()); 792 } 793 794 if (substringMatchingRule != null) 795 { 796 buffer.append(" SUBSTR "); 797 buffer.append(substringMatchingRule.getNameOrOID()); 798 } 799 800 // NOTE -- We will not include any approximate matching rule 801 // information here because it would break the standard and 802 // anything that depends on it. 803 // FIXME -- Should we encode this into one of the "extra" 804 // properties? 805 806 if (syntax != null) 807 { 808 buffer.append(" SYNTAX "); 809 buffer.append(syntax.getOID()); 810 } 811 812 if (isSingleValue) 813 { 814 buffer.append(" SINGLE-VALUE"); 815 } 816 817 if (isCollective) 818 { 819 buffer.append(" COLLECTIVE"); 820 } 821 822 if (isNoUserModification) 823 { 824 buffer.append(" NO-USER-MODIFICATION"); 825 } 826 827 if (attributeUsage != null) 828 { 829 buffer.append(" USAGE "); 830 buffer.append(attributeUsage.toString()); 831 } 832 } 833 } 834