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