001/* 002 * Copyright 2008-2024 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright 2008-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) 2008-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 com.unboundid.asn1.ASN1OctetString; 041import com.unboundid.ldap.sdk.LDAPException; 042import com.unboundid.ldap.sdk.ResultCode; 043import com.unboundid.util.NotNull; 044import com.unboundid.util.Nullable; 045import com.unboundid.util.ObjectPair; 046import com.unboundid.util.StaticUtils; 047import com.unboundid.util.ThreadSafety; 048import com.unboundid.util.ThreadSafetyLevel; 049import com.unboundid.util.Validator; 050 051import static com.unboundid.ldap.matchingrules.MatchingRuleMessages.*; 052 053 054 055/** 056 * This class provides an implementation of a matching rule that may be used for 057 * telephone numbers. It will accept values with any ASCII printable character. 058 * When making comparisons, spaces and dashes will be ignored. 059 */ 060@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 061public final class TelephoneNumberMatchingRule 062 extends SimpleMatchingRule 063{ 064 /** 065 * The name of the system property that may be used to specify the default 066 * comparison policy. If this is not specified, and if the default value is 067 * not overridden by the {@link #setDefaultComparisonPolicy} method, then a 068 * default policy of 069 * {@link TelephoneNumberComparisonPolicy#IGNORE_ALL_NON_NUMERIC_CHARACTERS} 070 * will be used. 071 */ 072 @NotNull public static final String DEFAULT_COMPARISON_POLICY_PROPERTY = 073 TelephoneNumberMatchingRule.class.getName() + 074 ".defaultComparisonPolicy"; 075 076 077 078 /** 079 * The name of the system property that may be used to specify the default 080 * validation policy. If this is not specified, and if the default value is 081 * not overridden by the {@link #setDefaultValidationPolicy} method, then a 082 * default policy of 083 * {@link TelephoneNumberValidationPolicy#ALLOW_NON_EMPTY_PRINTABLE_STRING} 084 * will be used. 085 */ 086 @NotNull public static final String DEFAULT_VALIDATION_POLICY_PROPERTY = 087 TelephoneNumberMatchingRule.class.getName() + 088 ".defaultValidationPolicy"; 089 090 091 092 /** 093 * The default comparison policy that will be used if none is specified. 094 */ 095 @NotNull private static TelephoneNumberComparisonPolicy 096 DEFAULT_COMPARISON_POLICY; 097 098 099 100 /** 101 * The default validation policy that will be used if none is specified. 102 */ 103 @NotNull private static TelephoneNumberValidationPolicy 104 DEFAULT_VALIDATION_POLICY; 105 106 107 108 /** 109 * The instance that will be returned from the {@code getInstance} method. 110 */ 111 @NotNull private static TelephoneNumberMatchingRule INSTANCE; 112 113 114 115 static 116 { 117 final ObjectPair<TelephoneNumberValidationPolicy, 118 TelephoneNumberComparisonPolicy> defaultPolicyPair = 119 computeDefaultPolicies(); 120 121 DEFAULT_VALIDATION_POLICY = defaultPolicyPair.getFirst(); 122 DEFAULT_COMPARISON_POLICY = defaultPolicyPair.getSecond(); 123 INSTANCE = new TelephoneNumberMatchingRule(DEFAULT_VALIDATION_POLICY, 124 DEFAULT_COMPARISON_POLICY); 125 } 126 127 128 129 /** 130 * The name for the telephoneNumberMatch equality matching rule. 131 */ 132 @NotNull public static final String EQUALITY_RULE_NAME = 133 "telephoneNumberMatch"; 134 135 136 137 /** 138 * The name for the telephoneNumberMatch equality matching rule, formatted in 139 * all lowercase characters. 140 */ 141 @NotNull static final String LOWER_EQUALITY_RULE_NAME = 142 StaticUtils.toLowerCase(EQUALITY_RULE_NAME); 143 144 145 146 /** 147 * The OID for the telephoneNumberMatch equality matching rule. 148 */ 149 @NotNull public static final String EQUALITY_RULE_OID = "2.5.13.20"; 150 151 152 153 /** 154 * The name for the telephoneNumberSubstringsMatch substring matching rule. 155 */ 156 @NotNull public static final String SUBSTRING_RULE_NAME = 157 "telephoneNumberSubstringsMatch"; 158 159 160 161 /** 162 * The name for the telephoneNumberSubstringsMatch substring matching rule, 163 * formatted in all lowercase characters. 164 */ 165 @NotNull static final String LOWER_SUBSTRING_RULE_NAME = 166 StaticUtils.toLowerCase(SUBSTRING_RULE_NAME); 167 168 169 170 /** 171 * The OID for the telephoneNumberSubstringsMatch substring matching rule. 172 */ 173 @NotNull public static final String SUBSTRING_RULE_OID = "2.5.13.21"; 174 175 176 177 /** 178 * The serial version UID for this serializable class. 179 */ 180 private static final long serialVersionUID = -5463096544849211252L; 181 182 183 184 // The policy to use when comparing telephone number values. 185 @NotNull private final TelephoneNumberComparisonPolicy comparisonPolicy; 186 187 // The policy to use when validating telephone number values. 188 @NotNull private final TelephoneNumberValidationPolicy validationPolicy; 189 190 191 192 /** 193 * Creates a new instance of this telephone number matching rule with the 194 * default validation and comparison policies. 195 */ 196 public TelephoneNumberMatchingRule() 197 { 198 this(DEFAULT_VALIDATION_POLICY, DEFAULT_COMPARISON_POLICY); 199 } 200 201 202 203 /** 204 * Creates a new instance of this telephone number matching rule with the 205 * specified validation and comparison policies. 206 * 207 * @param validationPolicy The policy to use when validating telephone 208 * number values. It must not be 209 * {@code null}. 210 * @param comparisonPolicy The policy to use when comparing telephone number 211 * values. It must not be {@code null}. 212 */ 213 public TelephoneNumberMatchingRule( 214 @NotNull final TelephoneNumberValidationPolicy validationPolicy, 215 @NotNull final TelephoneNumberComparisonPolicy comparisonPolicy) 216 { 217 Validator.ensureNotNullWithMessage(validationPolicy, 218 "TelephoneNumberMatchingRule.validationPolicy must not be null."); 219 Validator.ensureNotNullWithMessage(comparisonPolicy, 220 "TelephoneNumberMatchingRule.comparisonPolicy must not be null."); 221 222 this.validationPolicy = validationPolicy; 223 this.comparisonPolicy = comparisonPolicy; 224 } 225 226 227 228 /** 229 * Retrieves a singleton instance of this matching rule. 230 * 231 * @return A singleton instance of this matching rule. 232 */ 233 @NotNull() 234 public static TelephoneNumberMatchingRule getInstance() 235 { 236 return INSTANCE; 237 } 238 239 240 241 /** 242 * Retrieves the policy that will be used for validating telephone number 243 * values. 244 * 245 * @return The policy that will be used for validating telephone number 246 * values. 247 */ 248 @NotNull() 249 public TelephoneNumberValidationPolicy getValidationPolicy() 250 { 251 return validationPolicy; 252 } 253 254 255 256 /** 257 * Retrieves the policy that will be used for validating telephone number 258 * values when creating an instance of this matching rule using the default 259 * constructor. 260 * 261 * @return The policy that will be used for validating telephone number 262 * values when creating an instance of this matching rule using the 263 * default constructor. 264 */ 265 @NotNull() 266 public static TelephoneNumberValidationPolicy getDefaultValidationPolicy() 267 { 268 return DEFAULT_VALIDATION_POLICY; 269 } 270 271 272 273 /** 274 * Specifies the policy that will be used for validating telephone number 275 * values when creating an instance of this matching rule using the default 276 * constructor. 277 * 278 * @param defaultValidationPolicy The policy that will be used for 279 * validating telephone number values when 280 * creating an instance of this matching rule 281 * using the default constructor. 282 */ 283 public static synchronized void setDefaultValidationPolicy( 284 @NotNull final TelephoneNumberValidationPolicy defaultValidationPolicy) 285 { 286 Validator.ensureNotNullWithMessage(defaultValidationPolicy, 287 "TelephoneNumberMatchingRule.defaultValidationPolicy must not be " + 288 "null."); 289 290 DEFAULT_VALIDATION_POLICY = defaultValidationPolicy; 291 INSTANCE = new TelephoneNumberMatchingRule(DEFAULT_VALIDATION_POLICY, 292 DEFAULT_COMPARISON_POLICY); 293 } 294 295 296 297 /** 298 * Retrieves the policy that will be used for comparing telephone number 299 * values. 300 * 301 * @return The policy that will be used for comparing telephone number 302 * values. 303 */ 304 @NotNull() 305 public TelephoneNumberComparisonPolicy getComparisonPolicy() 306 { 307 return comparisonPolicy; 308 } 309 310 311 312 /** 313 * Retrieves the policy that will be used for comparing telephone number 314 * values when creating an instance of this matching rule using the default 315 * constructor. 316 * 317 * @return The policy that will be used for comparing telephone number 318 * values when creating an instance of this matching rule using the 319 * default constructor. 320 */ 321 @NotNull() 322 public static TelephoneNumberComparisonPolicy getDefaultComparisonPolicy() 323 { 324 return DEFAULT_COMPARISON_POLICY; 325 } 326 327 328 329 /** 330 * Specifies the policy that will be used for comparing telephone number 331 * values when creating an instance of this matching rule using the default 332 * constructor. 333 * 334 * @param defaultComparisonPolicy The policy that will be used for 335 * comparing telephone number values when 336 * creating an instance of this matching rule 337 * using the default constructor. 338 */ 339 public static synchronized void setDefaultComparisonPolicy( 340 @NotNull final TelephoneNumberComparisonPolicy defaultComparisonPolicy) 341 { 342 Validator.ensureNotNullWithMessage(defaultComparisonPolicy, 343 "TelephoneNumberMatchingRule.defaultComparisonPolicy must not be " + 344 "null."); 345 346 DEFAULT_COMPARISON_POLICY = defaultComparisonPolicy; 347 INSTANCE = new TelephoneNumberMatchingRule(DEFAULT_VALIDATION_POLICY, 348 DEFAULT_COMPARISON_POLICY); 349 } 350 351 352 353 /** 354 * {@inheritDoc} 355 */ 356 @Override() 357 @NotNull() 358 public String getEqualityMatchingRuleName() 359 { 360 return EQUALITY_RULE_NAME; 361 } 362 363 364 365 /** 366 * {@inheritDoc} 367 */ 368 @Override() 369 @NotNull() 370 public String getEqualityMatchingRuleOID() 371 { 372 return EQUALITY_RULE_OID; 373 } 374 375 376 377 /** 378 * {@inheritDoc} 379 */ 380 @Override() 381 @Nullable() 382 public String getOrderingMatchingRuleName() 383 { 384 return null; 385 } 386 387 388 389 /** 390 * {@inheritDoc} 391 */ 392 @Override() 393 @Nullable() 394 public String getOrderingMatchingRuleOID() 395 { 396 return null; 397 } 398 399 400 401 /** 402 * {@inheritDoc} 403 */ 404 @Override() 405 @NotNull() 406 public String getSubstringMatchingRuleName() 407 { 408 return SUBSTRING_RULE_NAME; 409 } 410 411 412 413 /** 414 * {@inheritDoc} 415 */ 416 @Override() 417 @NotNull() 418 public String getSubstringMatchingRuleOID() 419 { 420 return SUBSTRING_RULE_OID; 421 } 422 423 424 425 /** 426 * {@inheritDoc} 427 */ 428 @Override() 429 public int compareValues(@NotNull final ASN1OctetString value1, 430 @NotNull final ASN1OctetString value2) 431 throws LDAPException 432 { 433 throw new LDAPException(ResultCode.INAPPROPRIATE_MATCHING, 434 ERR_TELEPHONE_NUMBER_ORDERING_MATCHING_NOT_SUPPORTED.get()); 435 } 436 437 438 439 /** 440 * {@inheritDoc} 441 */ 442 @Override() 443 @NotNull() 444 public ASN1OctetString normalize(@NotNull final ASN1OctetString value) 445 throws LDAPException 446 { 447 validationPolicy.validateValue(value, false); 448 return comparisonPolicy.normalizeValue(value); 449 } 450 451 452 453 /** 454 * {@inheritDoc} 455 */ 456 @Override() 457 @NotNull() 458 public ASN1OctetString normalizeSubstring( 459 @NotNull final ASN1OctetString value, 460 final byte substringType) 461 throws LDAPException 462 { 463 validationPolicy.validateValue(value, true); 464 return comparisonPolicy.normalizeValue(value); 465 } 466 467 468 469 /** 470 * Computes the default validation and comparison policies that should be used 471 * for this class. 472 * 473 * @return An object pair in which the first element is the selected default 474 * validation policy and the second element is the selected default 475 * comparison policy. 476 */ 477 @NotNull() 478 static ObjectPair<TelephoneNumberValidationPolicy, 479 TelephoneNumberComparisonPolicy> computeDefaultPolicies() 480 { 481 // Determine the appropriate default validation policy. 482 TelephoneNumberValidationPolicy validationPolicy = null; 483 final String validationPropertyValue = 484 StaticUtils.getSystemProperty(DEFAULT_VALIDATION_POLICY_PROPERTY); 485 if (validationPropertyValue != null) 486 { 487 final String normalizedPropertyValue = 488 validationPropertyValue.toUpperCase().replace('-', '_'); 489 for (final TelephoneNumberValidationPolicy v : 490 TelephoneNumberValidationPolicy.values()) 491 { 492 if (v.name().equals(normalizedPropertyValue)) 493 { 494 validationPolicy = v; 495 break; 496 } 497 } 498 } 499 500 if (validationPolicy == null) 501 { 502 validationPolicy = 503 TelephoneNumberValidationPolicy.ALLOW_NON_EMPTY_PRINTABLE_STRING; 504 } 505 506 507 // Determine the appropriate default comparison policy. 508 TelephoneNumberComparisonPolicy comparisonPolicy = null; 509 final String comparisonPropertyValue = 510 StaticUtils.getSystemProperty(DEFAULT_COMPARISON_POLICY_PROPERTY); 511 if (comparisonPropertyValue != null) 512 { 513 final String normalizedPropertyValue = 514 comparisonPropertyValue.toUpperCase().replace('-', '_'); 515 for (final TelephoneNumberComparisonPolicy v : 516 TelephoneNumberComparisonPolicy.values()) 517 { 518 if (v.name().equals(normalizedPropertyValue)) 519 { 520 comparisonPolicy = v; 521 break; 522 } 523 } 524 } 525 526 if (comparisonPolicy == null) 527 { 528 comparisonPolicy = 529 TelephoneNumberComparisonPolicy.IGNORE_ALL_NON_NUMERIC_CHARACTERS; 530 } 531 532 533 return new ObjectPair<>(validationPolicy, comparisonPolicy); 534 } 535}