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