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