001/* 002 * Copyright 2007-2018 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2008-2018 Ping Identity Corporation 007 * 008 * This program is free software; you can redistribute it and/or modify 009 * it under the terms of the GNU General Public License (GPLv2 only) 010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 011 * as published by the Free Software Foundation. 012 * 013 * This program is distributed in the hope that it will be useful, 014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 016 * GNU General Public License for more details. 017 * 018 * You should have received a copy of the GNU General Public License 019 * along with this program; if not, see <http://www.gnu.org/licenses>. 020 */ 021package com.unboundid.ldap.matchingrules; 022 023 024 025import java.io.Serializable; 026 027import com.unboundid.asn1.ASN1OctetString; 028import com.unboundid.ldap.sdk.LDAPException; 029import com.unboundid.ldap.sdk.schema.AttributeTypeDefinition; 030import com.unboundid.ldap.sdk.schema.Schema; 031import com.unboundid.ldap.sdk.unboundidds.jsonfilter. 032 JSONObjectExactMatchingRule; 033import com.unboundid.util.Debug; 034import com.unboundid.util.Extensible; 035import com.unboundid.util.ThreadSafety; 036import com.unboundid.util.ThreadSafetyLevel; 037 038import static com.unboundid.util.StaticUtils.*; 039 040 041 042/** 043 * This class defines the API for an LDAP matching rule, which may be used to 044 * determine whether two values are equal to each other, and to normalize values 045 * so that they may be more easily compared. 046 */ 047@Extensible() 048@ThreadSafety(level=ThreadSafetyLevel.INTERFACE_THREADSAFE) 049public abstract class MatchingRule 050 implements Serializable 051{ 052 /** 053 * The substring element type used for subInitial substring assertion 054 * components. 055 */ 056 public static final byte SUBSTRING_TYPE_SUBINITIAL = (byte) 0x80; 057 058 059 060 /** 061 * The substring element type used for subAny substring assertion components. 062 */ 063 public static final byte SUBSTRING_TYPE_SUBANY = (byte) 0x81; 064 065 066 067 /** 068 * The substring element type used for subFinal substring assertion 069 * components. 070 */ 071 public static final byte SUBSTRING_TYPE_SUBFINAL = (byte) 0x82; 072 073 074 075 /** 076 * The serial version UID for this serializable class. 077 */ 078 private static final long serialVersionUID = 6050276733546358513L; 079 080 081 082 /** 083 * Creates a new instance of this matching rule. 084 */ 085 protected MatchingRule() 086 { 087 // No implementation is required. 088 } 089 090 091 092 /** 093 * Retrieves the name for this matching rule when used to perform equality 094 * matching, if appropriate. 095 * 096 * @return The name for this matching rule when used to perform equality 097 * matching, or {@code null} if this matching rule is not intended 098 * to be used for equality matching. 099 */ 100 public abstract String getEqualityMatchingRuleName(); 101 102 103 104 /** 105 * Retrieves the OID for this matching rule when used to perform equality 106 * matching, if appropriate. 107 * 108 * @return The OID for this matching rule when used to perform equality 109 * matching, or {@code null} if this matching rule is not intended 110 * to be used for equality matching. 111 */ 112 public abstract String getEqualityMatchingRuleOID(); 113 114 115 116 /** 117 * Retrieves the name for this matching rule when used to perform equality 118 * matching if defined, or the OID if no name is available. 119 * 120 * @return The name or OID for this matching rule when used to perform 121 * equality matching, or {@code null} if this matching rule cannot 122 * be used to perform equality matching. 123 */ 124 public String getEqualityMatchingRuleNameOrOID() 125 { 126 final String name = getEqualityMatchingRuleName(); 127 if (name == null) 128 { 129 return getEqualityMatchingRuleOID(); 130 } 131 else 132 { 133 return name; 134 } 135 } 136 137 138 139 /** 140 * Retrieves the name for this matching rule when used to perform ordering 141 * matching, if appropriate. 142 * 143 * @return The name for this matching rule when used to perform ordering 144 * matching, or {@code null} if this matching rule is not intended 145 * to be used for ordering matching. 146 */ 147 public abstract String getOrderingMatchingRuleName(); 148 149 150 151 /** 152 * Retrieves the OID for this matching rule when used to perform ordering 153 * matching, if appropriate. 154 * 155 * @return The OID for this matching rule when used to perform ordering 156 * matching, or {@code null} if this matching rule is not intended 157 * to be used for ordering matching. 158 */ 159 public abstract String getOrderingMatchingRuleOID(); 160 161 162 163 /** 164 * Retrieves the name for this matching rule when used to perform ordering 165 * matching if defined, or the OID if no name is available. 166 * 167 * @return The name or OID for this matching rule when used to perform 168 * ordering matching, or {@code null} if this matching rule cannot 169 * be used to perform equality matching. 170 */ 171 public String getOrderingMatchingRuleNameOrOID() 172 { 173 final String name = getOrderingMatchingRuleName(); 174 if (name == null) 175 { 176 return getOrderingMatchingRuleOID(); 177 } 178 else 179 { 180 return name; 181 } 182 } 183 184 185 186 /** 187 * Retrieves the name for this matching rule when used to perform substring 188 * matching, if appropriate. 189 * 190 * @return The name for this matching rule when used to perform substring 191 * matching, or {@code null} if this matching rule is not intended 192 * to be used for substring matching. 193 */ 194 public abstract String getSubstringMatchingRuleName(); 195 196 197 198 /** 199 * Retrieves the OID for this matching rule when used to perform substring 200 * matching, if appropriate. 201 * 202 * @return The OID for this matching rule when used to perform substring 203 * matching, or {@code null} if this matching rule is not intended 204 * to be used for substring matching. 205 */ 206 public abstract String getSubstringMatchingRuleOID(); 207 208 209 210 /** 211 * Retrieves the name for this matching rule when used to perform substring 212 * matching if defined, or the OID if no name is available. 213 * 214 * @return The name or OID for this matching rule when used to perform 215 * substring matching, or {@code null} if this matching rule cannot 216 * be used to perform equality matching. 217 */ 218 public String getSubstringMatchingRuleNameOrOID() 219 { 220 final String name = getSubstringMatchingRuleName(); 221 if (name == null) 222 { 223 return getSubstringMatchingRuleOID(); 224 } 225 else 226 { 227 return name; 228 } 229 } 230 231 232 233 /** 234 * Indicates whether the provided values are equal to each other, according to 235 * the constraints of this matching rule. 236 * 237 * @param value1 The first value for which to make the determination. 238 * @param value2 The second value for which to make the determination. 239 * 240 * @return {@code true} if the provided values are considered equal, or 241 * {@code false} if not. 242 * 243 * @throws LDAPException If a problem occurs while making the determination, 244 * or if this matching rule does not support equality 245 * matching. 246 */ 247 public abstract boolean valuesMatch(ASN1OctetString value1, 248 ASN1OctetString value2) 249 throws LDAPException; 250 251 252 253 /** 254 * Indicates whether the provided assertion value matches any of the provided 255 * attribute values. 256 * 257 * @param assertionValue The assertion value for which to make the 258 * determination. 259 * @param attributeValues The set of attribute values to compare against the 260 * provided assertion value. 261 * 262 * @return {@code true} if the provided assertion value matches any of the 263 * given attribute values, or {@code false} if not. 264 * 265 * @throws LDAPException If a problem occurs while making the determination, 266 * or if this matching rule does not support equality 267 * matching. 268 */ 269 public boolean matchesAnyValue(final ASN1OctetString assertionValue, 270 final ASN1OctetString[] attributeValues) 271 throws LDAPException 272 { 273 if ((assertionValue == null) || (attributeValues == null) || 274 (attributeValues.length == 0)) 275 { 276 return false; 277 } 278 279 boolean exceptionOnEveryAttempt = true; 280 LDAPException firstException = null; 281 for (final ASN1OctetString attributeValue : attributeValues) 282 { 283 try 284 { 285 if (valuesMatch(assertionValue, attributeValue)) 286 { 287 return true; 288 } 289 290 exceptionOnEveryAttempt = false; 291 } 292 catch (final LDAPException le) 293 { 294 Debug.debugException(le); 295 if (firstException == null) 296 { 297 firstException = le; 298 } 299 } 300 } 301 302 if (exceptionOnEveryAttempt) 303 { 304 throw firstException; 305 } 306 307 return false; 308 } 309 310 311 312 /** 313 * Indicates whether the provided value matches the given substring assertion, 314 * according to the constraints of this matching rule. 315 * 316 * @param value The value for which to make the determination. 317 * @param subInitial The subInitial portion of the substring assertion, or 318 * {@code null} if there is no subInitial element. 319 * @param subAny The subAny elements of the substring assertion, or 320 * {@code null} if there are no subAny elements. 321 * @param subFinal The subFinal portion of the substring assertion, or 322 * {@code null} if there is no subFinal element. 323 * 324 * @return {@code true} if the provided value matches the substring 325 * assertion, or {@code false} if not. 326 * 327 * @throws LDAPException If a problem occurs while making the determination, 328 * or if this matching rule does not support substring 329 * matching. 330 */ 331 public abstract boolean matchesSubstring(ASN1OctetString value, 332 ASN1OctetString subInitial, 333 ASN1OctetString[] subAny, 334 ASN1OctetString subFinal) 335 throws LDAPException; 336 337 338 339 /** 340 * Compares the provided values to determine their relative order in a sorted 341 * list. 342 * 343 * @param value1 The first value to compare. 344 * @param value2 The second value to compare. 345 * 346 * @return A negative value if {@code value1} should come before 347 * {@code value2} in a sorted list, a positive value if 348 * {@code value1} should come after {@code value2} in a sorted list, 349 * or zero if the values are equal or there is no distinction between 350 * their orders in a sorted list. 351 * 352 * @throws LDAPException If a problem occurs while making the determination, 353 * or if this matching rule does not support ordering 354 * matching. 355 */ 356 public abstract int compareValues(ASN1OctetString value1, 357 ASN1OctetString value2) 358 throws LDAPException; 359 360 361 362 /** 363 * Normalizes the provided value for easier matching. 364 * 365 * @param value The value to be normalized. 366 * 367 * @return The normalized form of the provided value. 368 * 369 * @throws LDAPException If a problem occurs while normalizing the provided 370 * value. 371 */ 372 public abstract ASN1OctetString normalize(ASN1OctetString value) 373 throws LDAPException; 374 375 376 377 /** 378 * Normalizes the provided value for use as part of a substring assertion. 379 * 380 * @param value The value to be normalized for use as part of a 381 * substring assertion. 382 * @param substringType The substring assertion component type for the 383 * provided value. It should be one of 384 * {@code SUBSTRING_TYPE_SUBINITIAL}, 385 * {@code SUBSTRING_TYPE_SUBANY}, or 386 * {@code SUBSTRING_TYPE_SUBFINAL}. 387 * 388 * @return The normalized form of the provided value. 389 * 390 * @throws LDAPException If a problem occurs while normalizing the provided 391 * value. 392 */ 393 public abstract ASN1OctetString normalizeSubstring(ASN1OctetString value, 394 byte substringType) 395 throws LDAPException; 396 397 398 399 /** 400 * Attempts to select the appropriate matching rule to use for equality 401 * matching against the specified attribute. If an appropriate matching rule 402 * cannot be determined, then the default equality matching rule will be 403 * selected. 404 * 405 * @param attrName The name of the attribute to examine in the provided 406 * schema. 407 * @param schema The schema to examine to make the appropriate 408 * determination. If this is {@code null}, then the default 409 * equality matching rule will be selected. 410 * 411 * @return The selected matching rule. 412 */ 413 public static MatchingRule selectEqualityMatchingRule(final String attrName, 414 final Schema schema) 415 { 416 return selectEqualityMatchingRule(attrName, null, schema); 417 } 418 419 420 421 /** 422 * Attempts to select the appropriate matching rule to use for equality 423 * matching against the specified attribute. If an appropriate matching rule 424 * cannot be determined, then the default equality matching rule will be 425 * selected. 426 * 427 * @param attrName The name of the attribute to examine in the provided 428 * schema. It may be {@code null} if the matching rule 429 * should be selected using the matching rule ID. 430 * @param ruleID The OID of the desired matching rule. It may be 431 * {@code null} if the matching rule should be selected only 432 * using the attribute name. If a rule ID is provided, then 433 * it will be the only criteria used to select the matching 434 * rule. 435 * @param schema The schema to examine to make the appropriate 436 * determination. If this is {@code null} and no rule ID 437 * was provided, then the default equality matching rule 438 * will be selected. 439 * 440 * @return The selected matching rule. 441 */ 442 public static MatchingRule selectEqualityMatchingRule(final String attrName, 443 final String ruleID, final Schema schema) 444 { 445 if (ruleID != null) 446 { 447 return selectEqualityMatchingRule(ruleID); 448 } 449 450 if ((attrName == null) || (schema == null)) 451 { 452 return getDefaultEqualityMatchingRule(); 453 } 454 455 final AttributeTypeDefinition attrType = schema.getAttributeType(attrName); 456 if (attrType == null) 457 { 458 return getDefaultEqualityMatchingRule(); 459 } 460 461 final String mrName = attrType.getEqualityMatchingRule(schema); 462 if (mrName != null) 463 { 464 return selectEqualityMatchingRule(mrName); 465 } 466 467 final String syntaxOID = attrType.getBaseSyntaxOID(schema); 468 if (syntaxOID != null) 469 { 470 return selectMatchingRuleForSyntax(syntaxOID); 471 } 472 473 return getDefaultEqualityMatchingRule(); 474 } 475 476 477 478 /** 479 * Attempts to select the appropriate matching rule to use for equality 480 * matching using the specified matching rule. If an appropriate matching 481 * rule cannot be determined, then the default equality matching rule will be 482 * selected. 483 * 484 * @param ruleID The name or OID of the desired matching rule. 485 * 486 * @return The selected matching rule. 487 */ 488 public static MatchingRule selectEqualityMatchingRule(final String ruleID) 489 { 490 if ((ruleID == null) || (ruleID.length() == 0)) 491 { 492 return getDefaultEqualityMatchingRule(); 493 } 494 495 final String lowerName = toLowerCase(ruleID); 496 if (lowerName.equals(BooleanMatchingRule.LOWER_EQUALITY_RULE_NAME) || 497 lowerName.equals(BooleanMatchingRule.EQUALITY_RULE_OID)) 498 { 499 return BooleanMatchingRule.getInstance(); 500 } 501 else if (lowerName.equals( 502 CaseExactStringMatchingRule.LOWER_EQUALITY_RULE_NAME) || 503 lowerName.equals(CaseExactStringMatchingRule.EQUALITY_RULE_OID) || 504 lowerName.equals("caseexactia5match") || 505 lowerName.equals("1.3.6.1.4.1.1466.109.114.1")) 506 { 507 return CaseExactStringMatchingRule.getInstance(); 508 } 509 else if (lowerName.equals( 510 CaseIgnoreListMatchingRule.LOWER_EQUALITY_RULE_NAME) || 511 lowerName.equals(CaseIgnoreListMatchingRule.EQUALITY_RULE_OID)) 512 { 513 return CaseIgnoreListMatchingRule.getInstance(); 514 } 515 else if (lowerName.equals( 516 CaseIgnoreStringMatchingRule.LOWER_EQUALITY_RULE_NAME) || 517 lowerName.equals(CaseIgnoreStringMatchingRule.EQUALITY_RULE_OID) || 518 lowerName.equals("caseignoreia5match") || 519 lowerName.equals("1.3.6.1.4.1.1466.109.114.2")) 520 { 521 return CaseIgnoreStringMatchingRule.getInstance(); 522 } 523 else if (lowerName.equals( 524 DistinguishedNameMatchingRule.LOWER_EQUALITY_RULE_NAME) || 525 lowerName.equals( 526 DistinguishedNameMatchingRule.EQUALITY_RULE_OID) || 527 lowerName.equals("uniquemembermatch") || 528 lowerName.equals("2.5.13.23")) 529 { 530 // NOTE -- Technically uniqueMember should use a name and optional UID 531 // matching rule, but the SDK doesn't currently provide one and the 532 // distinguished name matching rule should be sufficient the vast 533 // majority of the time. 534 return DistinguishedNameMatchingRule.getInstance(); 535 } 536 else if (lowerName.equals( 537 GeneralizedTimeMatchingRule.LOWER_EQUALITY_RULE_NAME) || 538 lowerName.equals(GeneralizedTimeMatchingRule.EQUALITY_RULE_OID)) 539 { 540 return GeneralizedTimeMatchingRule.getInstance(); 541 } 542 else if (lowerName.equals(IntegerMatchingRule.LOWER_EQUALITY_RULE_NAME) || 543 lowerName.equals(IntegerMatchingRule.EQUALITY_RULE_OID)) 544 { 545 return IntegerMatchingRule.getInstance(); 546 } 547 else if (lowerName.equals( 548 NumericStringMatchingRule.LOWER_EQUALITY_RULE_NAME) || 549 lowerName.equals(NumericStringMatchingRule.EQUALITY_RULE_OID)) 550 { 551 return NumericStringMatchingRule.getInstance(); 552 } 553 else if (lowerName.equals( 554 OctetStringMatchingRule.LOWER_EQUALITY_RULE_NAME) || 555 lowerName.equals(OctetStringMatchingRule.EQUALITY_RULE_OID)) 556 { 557 return OctetStringMatchingRule.getInstance(); 558 } 559 else if (lowerName.equals( 560 TelephoneNumberMatchingRule.LOWER_EQUALITY_RULE_NAME) || 561 lowerName.equals(TelephoneNumberMatchingRule.EQUALITY_RULE_OID)) 562 { 563 return TelephoneNumberMatchingRule.getInstance(); 564 } 565 else if (lowerName.equals("jsonobjectexactmatch") || 566 lowerName.equals("1.3.6.1.4.1.30221.2.4.12")) 567 { 568 return JSONObjectExactMatchingRule.getInstance(); 569 } 570 else 571 { 572 return getDefaultEqualityMatchingRule(); 573 } 574 } 575 576 577 578 /** 579 * Retrieves the default matching rule that will be used for equality matching 580 * if no other matching rule is specified or available. The rule returned 581 * will perform case-ignore string matching. 582 * 583 * @return The default matching rule that will be used for equality matching 584 * if no other matching rule is specified or available. 585 */ 586 public static MatchingRule getDefaultEqualityMatchingRule() 587 { 588 return CaseIgnoreStringMatchingRule.getInstance(); 589 } 590 591 592 593 /** 594 * Attempts to select the appropriate matching rule to use for ordering 595 * matching against the specified attribute. If an appropriate matching rule 596 * cannot be determined, then the default ordering matching rule will be 597 * selected. 598 * 599 * @param attrName The name of the attribute to examine in the provided 600 * schema. 601 * @param schema The schema to examine to make the appropriate 602 * determination. If this is {@code null}, then the default 603 * ordering matching rule will be selected. 604 * 605 * @return The selected matching rule. 606 */ 607 public static MatchingRule selectOrderingMatchingRule(final String attrName, 608 final Schema schema) 609 { 610 return selectOrderingMatchingRule(attrName, null, schema); 611 } 612 613 614 615 /** 616 * Attempts to select the appropriate matching rule to use for ordering 617 * matching against the specified attribute. If an appropriate matching rule 618 * cannot be determined, then the default ordering matching rule will be 619 * selected. 620 * 621 * @param attrName The name of the attribute to examine in the provided 622 * schema. It may be {@code null} if the matching rule 623 * should be selected using the matching rule ID. 624 * @param ruleID The OID of the desired matching rule. It may be 625 * {@code null} if the matching rule should be selected only 626 * using the attribute name. If a rule ID is provided, then 627 * it will be the only criteria used to select the matching 628 * rule. 629 * @param schema The schema to examine to make the appropriate 630 * determination. If this is {@code null} and no rule ID 631 * was provided, then the default ordering matching rule 632 * will be selected. 633 * 634 * @return The selected matching rule. 635 */ 636 public static MatchingRule selectOrderingMatchingRule(final String attrName, 637 final String ruleID, 638 final Schema schema) 639 { 640 if (ruleID != null) 641 { 642 return selectOrderingMatchingRule(ruleID); 643 } 644 645 if ((attrName == null) || (schema == null)) 646 { 647 return getDefaultOrderingMatchingRule(); 648 } 649 650 final AttributeTypeDefinition attrType = schema.getAttributeType(attrName); 651 if (attrType == null) 652 { 653 return getDefaultOrderingMatchingRule(); 654 } 655 656 final String mrName = attrType.getOrderingMatchingRule(schema); 657 if (mrName != null) 658 { 659 return selectOrderingMatchingRule(mrName); 660 } 661 662 final String syntaxOID = attrType.getBaseSyntaxOID(schema); 663 if (syntaxOID != null) 664 { 665 return selectMatchingRuleForSyntax(syntaxOID); 666 } 667 668 return getDefaultOrderingMatchingRule(); 669 } 670 671 672 673 /** 674 * Attempts to select the appropriate matching rule to use for ordering 675 * matching using the specified matching rule. If an appropriate matching 676 * rule cannot be determined, then the default ordering matching rule will be 677 * selected. 678 * 679 * @param ruleID The name or OID of the desired matching rule. 680 * 681 * @return The selected matching rule. 682 */ 683 public static MatchingRule selectOrderingMatchingRule(final String ruleID) 684 { 685 if ((ruleID == null) || (ruleID.length() == 0)) 686 { 687 return getDefaultOrderingMatchingRule(); 688 } 689 690 final String lowerName = toLowerCase(ruleID); 691 if (lowerName.equals( 692 CaseExactStringMatchingRule.LOWER_ORDERING_RULE_NAME) || 693 lowerName.equals(CaseExactStringMatchingRule.ORDERING_RULE_OID)) 694 { 695 return CaseExactStringMatchingRule.getInstance(); 696 } 697 else if (lowerName.equals( 698 CaseIgnoreStringMatchingRule.LOWER_ORDERING_RULE_NAME) || 699 lowerName.equals(CaseIgnoreStringMatchingRule.ORDERING_RULE_OID)) 700 { 701 return CaseIgnoreStringMatchingRule.getInstance(); 702 } 703 else if (lowerName.equals( 704 GeneralizedTimeMatchingRule.LOWER_ORDERING_RULE_NAME) || 705 lowerName.equals(GeneralizedTimeMatchingRule.ORDERING_RULE_OID)) 706 { 707 return GeneralizedTimeMatchingRule.getInstance(); 708 } 709 else if (lowerName.equals(IntegerMatchingRule.LOWER_ORDERING_RULE_NAME) || 710 lowerName.equals(IntegerMatchingRule.ORDERING_RULE_OID)) 711 { 712 return IntegerMatchingRule.getInstance(); 713 } 714 else if (lowerName.equals( 715 NumericStringMatchingRule.LOWER_ORDERING_RULE_NAME) || 716 lowerName.equals(NumericStringMatchingRule.ORDERING_RULE_OID)) 717 { 718 return NumericStringMatchingRule.getInstance(); 719 } 720 else if (lowerName.equals( 721 OctetStringMatchingRule.LOWER_ORDERING_RULE_NAME) || 722 lowerName.equals(OctetStringMatchingRule.ORDERING_RULE_OID)) 723 { 724 return OctetStringMatchingRule.getInstance(); 725 } 726 else 727 { 728 return getDefaultOrderingMatchingRule(); 729 } 730 } 731 732 733 734 /** 735 * Retrieves the default matching rule that will be used for ordering matching 736 * if no other matching rule is specified or available. The rule returned 737 * will perform case-ignore string matching. 738 * 739 * @return The default matching rule that will be used for ordering matching 740 * if no other matching rule is specified or available. 741 */ 742 public static MatchingRule getDefaultOrderingMatchingRule() 743 { 744 return CaseIgnoreStringMatchingRule.getInstance(); 745 } 746 747 748 749 /** 750 * Attempts to select the appropriate matching rule to use for substring 751 * matching against the specified attribute. If an appropriate matching rule 752 * cannot be determined, then the default substring matching rule will be 753 * selected. 754 * 755 * @param attrName The name of the attribute to examine in the provided 756 * schema. 757 * @param schema The schema to examine to make the appropriate 758 * determination. If this is {@code null}, then the default 759 * substring matching rule will be selected. 760 * 761 * @return The selected matching rule. 762 */ 763 public static MatchingRule selectSubstringMatchingRule(final String attrName, 764 final Schema schema) 765 { 766 return selectSubstringMatchingRule(attrName, null, schema); 767 } 768 769 770 771 /** 772 * Attempts to select the appropriate matching rule to use for substring 773 * matching against the specified attribute. If an appropriate matching rule 774 * cannot be determined, then the default substring matching rule will be 775 * selected. 776 * 777 * @param attrName The name of the attribute to examine in the provided 778 * schema. It may be {@code null} if the matching rule 779 * should be selected using the matching rule ID. 780 * @param ruleID The OID of the desired matching rule. It may be 781 * {@code null} if the matching rule should be selected only 782 * using the attribute name. If a rule ID is provided, then 783 * it will be the only criteria used to select the matching 784 * rule. 785 * @param schema The schema to examine to make the appropriate 786 * determination. If this is {@code null} and no rule ID 787 * was provided, then the default substring matching rule 788 * will be selected. 789 * 790 * @return The selected matching rule. 791 */ 792 public static MatchingRule selectSubstringMatchingRule(final String attrName, 793 final String ruleID, 794 final Schema schema) 795 { 796 if (ruleID != null) 797 { 798 return selectSubstringMatchingRule(ruleID); 799 } 800 801 if ((attrName == null) || (schema == null)) 802 { 803 return getDefaultSubstringMatchingRule(); 804 } 805 806 final AttributeTypeDefinition attrType = schema.getAttributeType(attrName); 807 if (attrType == null) 808 { 809 return getDefaultSubstringMatchingRule(); 810 } 811 812 final String mrName = attrType.getSubstringMatchingRule(schema); 813 if (mrName != null) 814 { 815 return selectSubstringMatchingRule(mrName); 816 } 817 818 final String syntaxOID = attrType.getBaseSyntaxOID(schema); 819 if (syntaxOID != null) 820 { 821 return selectMatchingRuleForSyntax(syntaxOID); 822 } 823 824 return getDefaultSubstringMatchingRule(); 825 } 826 827 828 829 /** 830 * Attempts to select the appropriate matching rule to use for substring 831 * matching using the specified matching rule. If an appropriate matching 832 * rule cannot be determined, then the default substring matching rule will be 833 * selected. 834 * 835 * @param ruleID The name or OID of the desired matching rule. 836 * 837 * @return The selected matching rule. 838 */ 839 public static MatchingRule selectSubstringMatchingRule(final String ruleID) 840 { 841 if ((ruleID == null) || (ruleID.length() == 0)) 842 { 843 return getDefaultSubstringMatchingRule(); 844 } 845 846 final String lowerName = toLowerCase(ruleID); 847 if (lowerName.equals( 848 CaseExactStringMatchingRule.LOWER_SUBSTRING_RULE_NAME) || 849 lowerName.equals(CaseExactStringMatchingRule.SUBSTRING_RULE_OID) || 850 lowerName.equals("caseexactia5substringsmatch")) 851 { 852 return CaseExactStringMatchingRule.getInstance(); 853 } 854 else if (lowerName.equals( 855 CaseIgnoreListMatchingRule.LOWER_SUBSTRING_RULE_NAME) || 856 lowerName.equals(CaseIgnoreListMatchingRule.SUBSTRING_RULE_OID)) 857 { 858 return CaseIgnoreListMatchingRule.getInstance(); 859 } 860 else if (lowerName.equals( 861 CaseIgnoreStringMatchingRule.LOWER_SUBSTRING_RULE_NAME) || 862 lowerName.equals( 863 CaseIgnoreStringMatchingRule.SUBSTRING_RULE_OID) || 864 lowerName.equals("caseignoreia5substringsmatch") || 865 lowerName.equals("1.3.6.1.4.1.1466.109.114.3")) 866 { 867 return CaseIgnoreStringMatchingRule.getInstance(); 868 } 869 else if (lowerName.equals( 870 NumericStringMatchingRule.LOWER_SUBSTRING_RULE_NAME) || 871 lowerName.equals(NumericStringMatchingRule.SUBSTRING_RULE_OID)) 872 { 873 return NumericStringMatchingRule.getInstance(); 874 } 875 else if (lowerName.equals( 876 OctetStringMatchingRule.LOWER_SUBSTRING_RULE_NAME) || 877 lowerName.equals(OctetStringMatchingRule.SUBSTRING_RULE_OID)) 878 { 879 return OctetStringMatchingRule.getInstance(); 880 } 881 else if (lowerName.equals( 882 TelephoneNumberMatchingRule.LOWER_SUBSTRING_RULE_NAME) || 883 lowerName.equals(TelephoneNumberMatchingRule.SUBSTRING_RULE_OID)) 884 { 885 return TelephoneNumberMatchingRule.getInstance(); 886 } 887 else 888 { 889 return getDefaultSubstringMatchingRule(); 890 } 891 } 892 893 894 895 /** 896 * Retrieves the default matching rule that will be used for substring 897 * matching if no other matching rule is specified or available. The rule 898 * returned will perform case-ignore string matching. 899 * 900 * @return The default matching rule that will be used for substring matching 901 * if no other matching rule is specified or available. 902 */ 903 public static MatchingRule getDefaultSubstringMatchingRule() 904 { 905 return CaseIgnoreStringMatchingRule.getInstance(); 906 } 907 908 909 910 /** 911 * Attempts to select the appropriate matching rule for use with the syntax 912 * with the specified OID. If an appropriate matching rule cannot be 913 * determined, then the case-ignore string matching rule will be selected. 914 * 915 * @param syntaxOID The OID of the attribute syntax for which to make the 916 * determination. 917 * 918 * @return The selected matching rule. 919 */ 920 public static MatchingRule selectMatchingRuleForSyntax(final String syntaxOID) 921 { 922 if (syntaxOID.equals("1.3.6.1.4.1.1466.115.121.1.7")) 923 { 924 return BooleanMatchingRule.getInstance(); 925 } 926 else if (syntaxOID.equals("1.3.6.1.4.1.1466.115.121.1.41")) // Postal addr. 927 { 928 return CaseIgnoreListMatchingRule.getInstance(); 929 } 930 else if (syntaxOID.equals("1.3.6.1.4.1.1466.115.121.1.12") || 931 syntaxOID.equals("1.3.6.1.4.1.1466.115.121.1.34")) // name&optional UID 932 { 933 return DistinguishedNameMatchingRule.getInstance(); 934 } 935 else if (syntaxOID.equals("1.3.6.1.4.1.1466.115.121.1.24") || 936 syntaxOID.equals("1.3.6.1.4.1.1466.115.121.1.53")) // UTC time 937 { 938 return GeneralizedTimeMatchingRule.getInstance(); 939 } 940 else if (syntaxOID.equals("1.3.6.1.4.1.1466.115.121.1.27")) 941 { 942 return IntegerMatchingRule.getInstance(); 943 } 944 else if (syntaxOID.equals("1.3.6.1.4.1.1466.115.121.1.36")) 945 { 946 return NumericStringMatchingRule.getInstance(); 947 } 948 else if (syntaxOID.equals("1.3.6.1.4.1.4203.1.1.2") || // auth password 949 syntaxOID.equals("1.3.6.1.4.1.1466.115.121.1.5") || // binary 950 syntaxOID.equals("1.3.6.1.4.1.1466.115.121.1.8") || // certificate 951 syntaxOID.equals("1.3.6.1.4.1.1466.115.121.1.9") || // cert list 952 syntaxOID.equals("1.3.6.1.4.1.1466.115.121.1.10") || // cert pair 953 syntaxOID.equals("1.3.6.1.4.1.1466.115.121.1.28") || // JPEG 954 syntaxOID.equals("1.3.6.1.4.1.1466.115.121.1.40")) // octet string 955 { 956 return OctetStringMatchingRule.getInstance(); 957 } 958 else if (syntaxOID.equals("1.3.6.1.4.1.1466.115.121.1.50")) 959 { 960 return TelephoneNumberMatchingRule.getInstance(); 961 } 962 else if (syntaxOID.equals("1.3.6.1.4.1.30221.2.3.4")) // JSON object exact 963 { 964 return JSONObjectExactMatchingRule.getInstance(); 965 } 966 else 967 { 968 return CaseIgnoreStringMatchingRule.getInstance(); 969 } 970 } 971}