001/* 002 * Copyright 2008-2020 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright 2008-2020 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-2020 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.sdk.controls; 037 038 039 040import java.io.Serializable; 041import java.util.ArrayList; 042import java.util.Arrays; 043 044import com.unboundid.asn1.ASN1Element; 045import com.unboundid.asn1.ASN1OctetString; 046import com.unboundid.asn1.ASN1Sequence; 047import com.unboundid.ldap.sdk.Filter; 048import com.unboundid.ldap.sdk.LDAPException; 049import com.unboundid.ldap.sdk.ResultCode; 050import com.unboundid.util.Debug; 051import com.unboundid.util.NotMutable; 052import com.unboundid.util.StaticUtils; 053import com.unboundid.util.ThreadSafety; 054import com.unboundid.util.ThreadSafetyLevel; 055import com.unboundid.util.Validator; 056 057import static com.unboundid.ldap.sdk.controls.ControlMessages.*; 058 059 060 061/** 062 * This class provides an implementation of the simple filter item for use with 063 * the {@link MatchedValuesRequestControl} as defined in 064 * <A HREF="http://www.ietf.org/rfc/rfc3876.txt">RFC 3876</A>. It is similar to 065 * a search filter (see the {@link Filter} class), but may only contain a single 066 * element (i.e., no AND, OR, or NOT components are allowed), and extensible 067 * matching does not allow the use of the dnAttributes field. 068 */ 069@NotMutable() 070@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 071public final class MatchedValuesFilter 072 implements Serializable 073{ 074 /** 075 * The match type that will be used for equality match filters. 076 */ 077 public static final byte MATCH_TYPE_EQUALITY = (byte) 0xA3; 078 079 080 081 /** 082 * The match type that will be used for substring match filters. 083 */ 084 public static final byte MATCH_TYPE_SUBSTRINGS = (byte) 0xA4; 085 086 087 088 /** 089 * The match type that will be used for greater-or-equal match filters. 090 */ 091 public static final byte MATCH_TYPE_GREATER_OR_EQUAL = (byte) 0xA5; 092 093 094 095 /** 096 * The match type that will be used for less-or-equal match filters. 097 */ 098 public static final byte MATCH_TYPE_LESS_OR_EQUAL = (byte) 0xA6; 099 100 101 102 /** 103 * The match type that will be used for presence match filters. 104 */ 105 public static final byte MATCH_TYPE_PRESENT = (byte) 0x87; 106 107 108 109 /** 110 * The match type that will be used for approximate match filters. 111 */ 112 public static final byte MATCH_TYPE_APPROXIMATE = (byte) 0xA8; 113 114 115 116 /** 117 * The match type that will be used for extensible match filters. 118 */ 119 public static final byte MATCH_TYPE_EXTENSIBLE = (byte) 0xA9; 120 121 122 123 /** 124 * The BER type for the subInitial substring filter element. 125 */ 126 private static final byte SUBSTRING_TYPE_SUBINITIAL = (byte) 0x80; 127 128 129 130 /** 131 * The BER type for the subAny substring filter element. 132 */ 133 private static final byte SUBSTRING_TYPE_SUBANY = (byte) 0x81; 134 135 136 137 /** 138 * The BER type for the subFinal substring filter element. 139 */ 140 private static final byte SUBSTRING_TYPE_SUBFINAL = (byte) 0x82; 141 142 143 144 /** 145 * The BER type for the matching rule ID extensible match filter element. 146 */ 147 private static final byte EXTENSIBLE_TYPE_MATCHING_RULE_ID = (byte) 0x81; 148 149 150 151 /** 152 * The BER type for the attribute name extensible match filter element. 153 */ 154 private static final byte EXTENSIBLE_TYPE_ATTRIBUTE_NAME = (byte) 0x82; 155 156 157 158 /** 159 * The BER type for the match value extensible match filter element. 160 */ 161 private static final byte EXTENSIBLE_TYPE_MATCH_VALUE = (byte) 0x83; 162 163 164 165 /** 166 * An empty array that will be used if there are no subAny elements. 167 */ 168 private static final ASN1OctetString[] NO_SUB_ANY = new ASN1OctetString[0]; 169 170 171 172 /** 173 * An empty array that will be used if there are no subAny elements. 174 */ 175 private static final String[] NO_SUB_ANY_STRINGS = StaticUtils.NO_STRINGS; 176 177 178 179 /** 180 * An empty array that will be used if there are no subAny elements. 181 */ 182 private static final byte[][] NO_SUB_ANY_BYTES = new byte[0][]; 183 184 185 186 /** 187 * The serial version UID for this serializable class. 188 */ 189 private static final long serialVersionUID = 8144732301100674661L; 190 191 192 193 // The name of the attribute type to include in this filter, if appropriate. 194 private final ASN1OctetString assertionValue; 195 196 // The subFinal value for this filter, if appropriate. 197 private final ASN1OctetString subFinalValue; 198 199 // The subInitial value for this filter, if appropriate. 200 private final ASN1OctetString subInitialValue; 201 202 // The subAny values for this filter, if appropriate. 203 private final ASN1OctetString[] subAnyValues; 204 205 // The filter type for this filter. 206 private final byte matchType; 207 208 // The name of the attribute type to include in this filter, if appropriate. 209 private final String attributeType; 210 211 // The matching rule ID for this filter, if appropriate. 212 private final String matchingRuleID; 213 214 215 216 /** 217 * Creates a new matched values filter with the provided information. 218 * 219 * @param matchType The filter type for this filter. 220 * @param attributeType The name of the attribute type. It may be 221 * {@code null} only for extensible match filters and 222 * only if a non-{@code null} matching rule ID is 223 * provided. 224 * @param assertionValue The assertion value for this filter. It may only 225 * be {@code null} for substring and presence 226 * filters. 227 * @param subInitialValue The subInitial value for this filter. It may only 228 * be provided for substring filters. 229 * @param subAnyValues The set of subAny values for this filter. It may 230 * only be provided for substring filters. 231 * @param subFinalValue The subFinal value for this filter. It may only 232 * be provided for substring filters. 233 * @param matchingRuleID The matching rule ID for this filter. It may only 234 * be provided for extensible match filters. 235 */ 236 private MatchedValuesFilter(final byte matchType, final String attributeType, 237 final ASN1OctetString assertionValue, 238 final ASN1OctetString subInitialValue, 239 final ASN1OctetString[] subAnyValues, 240 final ASN1OctetString subFinalValue, 241 final String matchingRuleID) 242 { 243 this.matchType = matchType; 244 this.attributeType = attributeType; 245 this.assertionValue = assertionValue; 246 this.subInitialValue = subInitialValue; 247 this.subAnyValues = subAnyValues; 248 this.subFinalValue = subFinalValue; 249 this.matchingRuleID = matchingRuleID; 250 } 251 252 253 254 /** 255 * Creates a new matched values filter for equality matching with the provided 256 * information. 257 * 258 * @param attributeType The attribute type for the filter. It must not be 259 * {@code null}. 260 * @param assertionValue The assertion value for the filter. It must not be 261 * {@code null}. 262 * 263 * @return The created equality match filter. 264 */ 265 public static MatchedValuesFilter createEqualityFilter( 266 final String attributeType, 267 final String assertionValue) 268 { 269 Validator.ensureNotNull(attributeType, assertionValue); 270 271 return new MatchedValuesFilter(MATCH_TYPE_EQUALITY, attributeType, 272 new ASN1OctetString(assertionValue), null, NO_SUB_ANY, null, null); 273 } 274 275 276 277 /** 278 * Creates a new matched values filter for equality matching with the provided 279 * information. 280 * 281 * @param attributeType The attribute type for the filter. It must not be 282 * {@code null}. 283 * @param assertionValue The assertion value for the filter. It must not be 284 * {@code null}. 285 * 286 * @return The created equality match filter. 287 */ 288 public static MatchedValuesFilter createEqualityFilter( 289 final String attributeType, 290 final byte[] assertionValue) 291 { 292 Validator.ensureNotNull(attributeType, assertionValue); 293 294 return new MatchedValuesFilter(MATCH_TYPE_EQUALITY, attributeType, 295 new ASN1OctetString(assertionValue), null, NO_SUB_ANY, null, null); 296 } 297 298 299 300 /** 301 * Creates a new matched values filter for substring matching with the 302 * provided information. At least one substring filter element must be 303 * provided. 304 * 305 * @param attributeType The attribute type for the filter. It must not be 306 * {@code null}. 307 * @param subInitialValue The subInitial value for the filter, or 308 * {@code null} if there is no subInitial element. 309 * @param subAnyValues The set of subAny values for the filter, or 310 * {@code null} if there are no subAny elements. 311 * @param subFinalValue The subFinal value for the filter, or {@code null} 312 * if there is no subFinal element. 313 * 314 * @return The created equality match filter. 315 */ 316 public static MatchedValuesFilter createSubstringFilter( 317 final String attributeType, 318 final String subInitialValue, 319 final String[] subAnyValues, 320 final String subFinalValue) 321 { 322 Validator.ensureNotNull(attributeType); 323 Validator.ensureTrue((subInitialValue != null) || 324 ((subAnyValues != null) && (subAnyValues.length > 0)) || 325 (subFinalValue != null)); 326 327 final ASN1OctetString subInitialOS; 328 if (subInitialValue == null) 329 { 330 subInitialOS = null; 331 } 332 else 333 { 334 subInitialOS = new ASN1OctetString(SUBSTRING_TYPE_SUBINITIAL, 335 subInitialValue); 336 } 337 338 final ASN1OctetString[] subAnyOS; 339 if ((subAnyValues == null) || (subAnyValues.length == 0)) 340 { 341 subAnyOS = NO_SUB_ANY; 342 } 343 else 344 { 345 subAnyOS = new ASN1OctetString[subAnyValues.length]; 346 for (int i=0; i < subAnyValues.length; i++) 347 { 348 subAnyOS[i] = new ASN1OctetString(SUBSTRING_TYPE_SUBANY, 349 subAnyValues[i]); 350 } 351 } 352 353 final ASN1OctetString subFinalOS; 354 if (subFinalValue == null) 355 { 356 subFinalOS = null; 357 } 358 else 359 { 360 subFinalOS = new ASN1OctetString(SUBSTRING_TYPE_SUBFINAL, subFinalValue); 361 } 362 363 return new MatchedValuesFilter(MATCH_TYPE_SUBSTRINGS, attributeType, null, 364 subInitialOS, subAnyOS, subFinalOS, null); 365 } 366 367 368 369 /** 370 * Creates a new matched values filter for substring matching with the 371 * provided information. At least one substring filter element must be 372 * provided. 373 * 374 * @param attributeType The attribute type for the filter. It must not be 375 * {@code null}. 376 * @param subInitialValue The subInitial value for the filter, or 377 * {@code null} if there is no subInitial element. 378 * @param subAnyValues The set of subAny values for the filter, or 379 * {@code null} if there are no subAny elements. 380 * @param subFinalValue The subFinal value for the filter, or {@code null} 381 * if there is no subFinal element. 382 * 383 * @return The created equality match filter. 384 */ 385 public static MatchedValuesFilter createSubstringFilter( 386 final String attributeType, 387 final byte[] subInitialValue, 388 final byte[][] subAnyValues, 389 final byte[] subFinalValue) 390 { 391 Validator.ensureNotNull(attributeType); 392 Validator.ensureTrue((subInitialValue != null) || 393 ((subAnyValues != null) && (subAnyValues.length > 0)) || 394 (subFinalValue != null)); 395 396 final ASN1OctetString subInitialOS; 397 if (subInitialValue == null) 398 { 399 subInitialOS = null; 400 } 401 else 402 { 403 subInitialOS = new ASN1OctetString(SUBSTRING_TYPE_SUBINITIAL, 404 subInitialValue); 405 } 406 407 final ASN1OctetString[] subAnyOS; 408 if ((subAnyValues == null) || (subAnyValues.length == 0)) 409 { 410 subAnyOS = NO_SUB_ANY; 411 } 412 else 413 { 414 subAnyOS = new ASN1OctetString[subAnyValues.length]; 415 for (int i=0; i < subAnyValues.length; i++) 416 { 417 subAnyOS[i] = new ASN1OctetString(SUBSTRING_TYPE_SUBANY, 418 subAnyValues[i]); 419 } 420 } 421 422 final ASN1OctetString subFinalOS; 423 if (subFinalValue == null) 424 { 425 subFinalOS = null; 426 } 427 else 428 { 429 subFinalOS = new ASN1OctetString(SUBSTRING_TYPE_SUBFINAL, subFinalValue); 430 } 431 432 return new MatchedValuesFilter(MATCH_TYPE_SUBSTRINGS, attributeType, null, 433 subInitialOS, subAnyOS, subFinalOS, null); 434 } 435 436 437 438 /** 439 * Creates a new matched values filter for greater-or-equal matching with the 440 * provided information. 441 * 442 * @param attributeType The attribute type for the filter. It must not be 443 * {@code null}. 444 * @param assertionValue The assertion value for the filter. It must not be 445 * {@code null}. 446 * 447 * @return The created greater-or-equal match filter. 448 */ 449 public static MatchedValuesFilter createGreaterOrEqualFilter( 450 final String attributeType, 451 final String assertionValue) 452 { 453 Validator.ensureNotNull(attributeType, assertionValue); 454 455 return new MatchedValuesFilter(MATCH_TYPE_GREATER_OR_EQUAL, attributeType, 456 new ASN1OctetString(assertionValue), null, 457 NO_SUB_ANY, null, null); 458 } 459 460 461 462 /** 463 * Creates a new matched values filter for greater-or-equal matching with the 464 * provided information. 465 * 466 * @param attributeType The attribute type for the filter. It must not be 467 * {@code null}. 468 * @param assertionValue The assertion value for the filter. It must not be 469 * {@code null}. 470 * 471 * @return The created greater-or-equal match filter. 472 */ 473 public static MatchedValuesFilter createGreaterOrEqualFilter( 474 final String attributeType, 475 final byte[] assertionValue) 476 { 477 Validator.ensureNotNull(attributeType, assertionValue); 478 479 return new MatchedValuesFilter(MATCH_TYPE_GREATER_OR_EQUAL, attributeType, 480 new ASN1OctetString(assertionValue), null, 481 NO_SUB_ANY, null, null); 482 } 483 484 485 486 /** 487 * Creates a new matched values filter for less-or-equal matching with the 488 * provided information. 489 * 490 * @param attributeType The attribute type for the filter. It must not be 491 * {@code null}. 492 * @param assertionValue The assertion value for the filter. It must not be 493 * {@code null}. 494 * 495 * @return The created less-or-equal match filter. 496 */ 497 public static MatchedValuesFilter createLessOrEqualFilter( 498 final String attributeType, 499 final String assertionValue) 500 { 501 Validator.ensureNotNull(attributeType, assertionValue); 502 503 return new MatchedValuesFilter(MATCH_TYPE_LESS_OR_EQUAL, attributeType, 504 new ASN1OctetString(assertionValue), null, 505 NO_SUB_ANY, null, null); 506 } 507 508 509 510 /** 511 * Creates a new matched values filter for less-or-equal matching with the 512 * provided information. 513 * 514 * @param attributeType The attribute type for the filter. It must not be 515 * {@code null}. 516 * @param assertionValue The assertion value for the filter. It must not be 517 * {@code null}. 518 * 519 * @return The created less-or-equal match filter. 520 */ 521 public static MatchedValuesFilter createLessOrEqualFilter( 522 final String attributeType, 523 final byte[] assertionValue) 524 { 525 Validator.ensureNotNull(attributeType, assertionValue); 526 527 return new MatchedValuesFilter(MATCH_TYPE_LESS_OR_EQUAL, attributeType, 528 new ASN1OctetString(assertionValue), null, 529 NO_SUB_ANY, null, null); 530 } 531 532 533 534 /** 535 * Creates a new matched values filter for presence matching with the provided 536 * information. 537 * 538 * @param attributeType The attribute type for the filter. It must not be 539 * {@code null}. 540 * 541 * @return The created present match filter. 542 */ 543 public static MatchedValuesFilter createPresentFilter( 544 final String attributeType) 545 { 546 Validator.ensureNotNull(attributeType); 547 548 return new MatchedValuesFilter(MATCH_TYPE_PRESENT, attributeType, null, 549 null, NO_SUB_ANY, null, null); 550 } 551 552 553 554 /** 555 * Creates a new matched values filter for approximate matching with the 556 * provided information. 557 * 558 * @param attributeType The attribute type for the filter. It must not be 559 * {@code null}. 560 * @param assertionValue The assertion value for the filter. It must not be 561 * {@code null}. 562 * 563 * @return The created approximate match filter. 564 */ 565 public static MatchedValuesFilter createApproximateFilter( 566 final String attributeType, 567 final String assertionValue) 568 { 569 Validator.ensureNotNull(attributeType, assertionValue); 570 571 return new MatchedValuesFilter(MATCH_TYPE_APPROXIMATE, attributeType, 572 new ASN1OctetString(assertionValue), null, 573 NO_SUB_ANY, null, null); 574 } 575 576 577 578 /** 579 * Creates a new matched values filter for approximate matching with the 580 * provided information. 581 * 582 * @param attributeType The attribute type for the filter. It must not be 583 * {@code null}. 584 * @param assertionValue The assertion value for the filter. It must not be 585 * {@code null}. 586 * 587 * @return The created greater-or-equal match filter. 588 */ 589 public static MatchedValuesFilter createApproximateFilter( 590 final String attributeType, 591 final byte[] assertionValue) 592 { 593 Validator.ensureNotNull(attributeType, assertionValue); 594 595 return new MatchedValuesFilter(MATCH_TYPE_APPROXIMATE, attributeType, 596 new ASN1OctetString(assertionValue), null, 597 NO_SUB_ANY, null, null); 598 } 599 600 601 602 /** 603 * Creates a new matched values filter for extensible matching with the 604 * provided information. At least one of the attribute type and matching rule 605 * ID must be provided. 606 * 607 * @param attributeType The attribute type for the filter, or {@code null} 608 * if there is no attribute type. 609 * @param matchingRuleID The matching rule ID for the filter, or 610 * {@code null} if there is no matching rule ID. 611 * @param assertionValue The assertion value for the filter. It must not be 612 * {@code null}. 613 * 614 * @return The created extensible match filter. 615 */ 616 public static MatchedValuesFilter createExtensibleMatchFilter( 617 final String attributeType, 618 final String matchingRuleID, 619 final String assertionValue) 620 { 621 Validator.ensureNotNull(assertionValue); 622 Validator.ensureTrue((attributeType != null) || (matchingRuleID != null)); 623 624 final ASN1OctetString matchValue = 625 new ASN1OctetString(EXTENSIBLE_TYPE_MATCH_VALUE, assertionValue); 626 627 return new MatchedValuesFilter(MATCH_TYPE_EXTENSIBLE, attributeType, 628 matchValue, null, NO_SUB_ANY, null, 629 matchingRuleID); 630 } 631 632 633 634 /** 635 * Creates a new matched values filter for extensible matching with the 636 * provided information. At least one of the attribute type and matching rule 637 * ID must be provided. 638 * 639 * @param attributeType The attribute type for the filter, or {@code null} 640 * if there is no attribute type. 641 * @param matchingRuleID The matching rule ID for the filter, or 642 * {@code null} if there is no matching rule ID. 643 * @param assertionValue The assertion value for the filter. It must not be 644 * {@code null}. 645 * 646 * @return The created extensible match filter. 647 */ 648 public static MatchedValuesFilter createExtensibleMatchFilter( 649 final String attributeType, 650 final String matchingRuleID, 651 final byte[] assertionValue) 652 { 653 Validator.ensureNotNull(assertionValue); 654 Validator.ensureTrue((attributeType != null) || (matchingRuleID != null)); 655 656 final ASN1OctetString matchValue = 657 new ASN1OctetString(EXTENSIBLE_TYPE_MATCH_VALUE, assertionValue); 658 659 return new MatchedValuesFilter(MATCH_TYPE_EXTENSIBLE, attributeType, 660 matchValue, null, NO_SUB_ANY, null, 661 matchingRuleID); 662 } 663 664 665 666 /** 667 * Creates a new matched values filter from the provided search filter, if 668 * possible. 669 * 670 * @param filter The search filter to use to create this matched values 671 * filter. 672 * 673 * @return The search filter that corresponds to this matched values filter. 674 * 675 * @throws LDAPException If the provided search filter cannot be represented 676 * as a matched values filter. 677 */ 678 public static MatchedValuesFilter create(final Filter filter) 679 throws LDAPException 680 { 681 switch (filter.getFilterType()) 682 { 683 case Filter.FILTER_TYPE_AND: 684 throw new LDAPException(ResultCode.DECODING_ERROR, 685 ERR_MV_FILTER_AND_NOT_SUPPORTED.get()); 686 687 case Filter.FILTER_TYPE_OR: 688 throw new LDAPException(ResultCode.DECODING_ERROR, 689 ERR_MV_FILTER_OR_NOT_SUPPORTED.get()); 690 691 case Filter.FILTER_TYPE_NOT: 692 throw new LDAPException(ResultCode.DECODING_ERROR, 693 ERR_MV_FILTER_NOT_NOT_SUPPORTED.get()); 694 695 case Filter.FILTER_TYPE_EQUALITY: 696 return createEqualityFilter(filter.getAttributeName(), 697 filter.getAssertionValueBytes()); 698 699 case Filter.FILTER_TYPE_SUBSTRING: 700 return createSubstringFilter(filter.getAttributeName(), 701 filter.getSubInitialBytes(), filter.getSubAnyBytes(), 702 filter.getSubFinalBytes()); 703 704 case Filter.FILTER_TYPE_GREATER_OR_EQUAL: 705 return createGreaterOrEqualFilter(filter.getAttributeName(), 706 filter.getAssertionValueBytes()); 707 708 case Filter.FILTER_TYPE_LESS_OR_EQUAL: 709 return createLessOrEqualFilter(filter.getAttributeName(), 710 filter.getAssertionValueBytes()); 711 712 case Filter.FILTER_TYPE_PRESENCE: 713 return createPresentFilter(filter.getAttributeName()); 714 715 case Filter.FILTER_TYPE_APPROXIMATE_MATCH: 716 return createApproximateFilter(filter.getAttributeName(), 717 filter.getAssertionValueBytes()); 718 719 case Filter.FILTER_TYPE_EXTENSIBLE_MATCH: 720 if (filter.getDNAttributes()) 721 { 722 throw new LDAPException(ResultCode.DECODING_ERROR, 723 ERR_MV_FILTER_DNATTRS_NOT_SUPPORTED.get()); 724 } 725 726 return createExtensibleMatchFilter(filter.getAttributeName(), 727 filter.getMatchingRuleID(), 728 filter.getAssertionValueBytes()); 729 730 default: 731 // This should never happen. 732 throw new LDAPException(ResultCode.DECODING_ERROR, 733 ERR_MV_FILTER_INVALID_FILTER_TYPE.get( 734 StaticUtils.toHex(filter.getFilterType()))); 735 } 736 } 737 738 739 740 /** 741 * Retrieves the match type for this matched values filter. 742 * 743 * @return The match type for this matched values filter. 744 */ 745 public byte getMatchType() 746 { 747 return matchType; 748 } 749 750 751 752 /** 753 * Retrieves the name of the attribute type for this matched values filter, 754 * if available. 755 * 756 * @return The name of the attribute type for this matched values filter, or 757 * {@code null} if there is none. 758 */ 759 public String getAttributeType() 760 { 761 return attributeType; 762 } 763 764 765 766 /** 767 * Retrieves the string representation of the assertion value for this matched 768 * values filter, if available. 769 * 770 * @return The string representation of the assertion value for this matched 771 * values filter, or {@code null} if there is none. 772 */ 773 public String getAssertionValue() 774 { 775 if (assertionValue == null) 776 { 777 return null; 778 } 779 else 780 { 781 return assertionValue.stringValue(); 782 } 783 } 784 785 786 787 /** 788 * Retrieves the binary representation of the assertion value for this matched 789 * values filter, if available. 790 * 791 * @return The binary representation of the assertion value for this matched 792 * values filter, or {@code null} if there is none. 793 */ 794 public byte[] getAssertionValueBytes() 795 { 796 if (assertionValue == null) 797 { 798 return null; 799 } 800 else 801 { 802 return assertionValue.getValue(); 803 } 804 } 805 806 807 808 /** 809 * Retrieves raw assertion value for this matched values filter, if available. 810 * 811 * @return The raw assertion value for this matched values filter, or 812 * {@code null} if there is none. 813 */ 814 public ASN1OctetString getRawAssertionValue() 815 { 816 return assertionValue; 817 } 818 819 820 821 /** 822 * Retrieves the string representation of the subInitial element for this 823 * matched values filter, if available. 824 * 825 * @return The string representation of the subInitial element for this 826 * matched values filter, or {@code null} if there is none. 827 */ 828 public String getSubInitialValue() 829 { 830 if (subInitialValue == null) 831 { 832 return null; 833 } 834 else 835 { 836 return subInitialValue.stringValue(); 837 } 838 } 839 840 841 842 /** 843 * Retrieves the binary representation of the subInitial element for this 844 * matched values filter, if available. 845 * 846 * @return The binary representation of the subInitial element for this 847 * matched values filter, or {@code null} if there is none. 848 */ 849 public byte[] getSubInitialValueBytes() 850 { 851 if (subInitialValue == null) 852 { 853 return null; 854 } 855 else 856 { 857 return subInitialValue.getValue(); 858 } 859 } 860 861 862 863 /** 864 * Retrieves the raw subInitial element for this matched values filter, if 865 * available. 866 * 867 * @return The raw subInitial element for this matched values filter, or 868 * {@code null} if there is none. 869 */ 870 public ASN1OctetString getRawSubInitialValue() 871 { 872 return subInitialValue; 873 } 874 875 876 877 /** 878 * Retrieves the string representations of the subAny elements for this 879 * matched values filter, if available. 880 * 881 * @return The string representations of the subAny element for this matched 882 * values filter, or an empty array if there are none. 883 */ 884 public String[] getSubAnyValues() 885 { 886 if (subAnyValues.length == 0) 887 { 888 return NO_SUB_ANY_STRINGS; 889 } 890 else 891 { 892 final String[] subAnyStrings = new String[subAnyValues.length]; 893 for (int i=0; i < subAnyValues.length; i++) 894 { 895 subAnyStrings[i] = subAnyValues[i].stringValue(); 896 } 897 898 return subAnyStrings; 899 } 900 } 901 902 903 904 /** 905 * Retrieves the binary representations of the subAny elements for this 906 * matched values filter, if available. 907 * 908 * @return The binary representations of the subAny element for this matched 909 * values filter, or an empty array if there are none. 910 */ 911 public byte[][] getSubAnyValueBytes() 912 { 913 if (subAnyValues.length == 0) 914 { 915 return NO_SUB_ANY_BYTES; 916 } 917 else 918 { 919 final byte[][] subAnyBytes = new byte[subAnyValues.length][]; 920 for (int i=0; i < subAnyValues.length; i++) 921 { 922 subAnyBytes[i] = subAnyValues[i].getValue(); 923 } 924 925 return subAnyBytes; 926 } 927 } 928 929 930 931 /** 932 * Retrieves the raw subAny elements for this matched values filter, if 933 * available. 934 * 935 * @return The raw subAny element for this matched values filter, or an empty 936 * array if there are none. 937 */ 938 public ASN1OctetString[] getRawSubAnyValues() 939 { 940 return subAnyValues; 941 } 942 943 944 945 /** 946 * Retrieves the string representation of the subFinal element for this 947 * matched values filter, if available. 948 * 949 * @return The string representation of the subFinal element for this 950 * matched values filter, or {@code null} if there is none. 951 */ 952 public String getSubFinalValue() 953 { 954 if (subFinalValue == null) 955 { 956 return null; 957 } 958 else 959 { 960 return subFinalValue.stringValue(); 961 } 962 } 963 964 965 966 /** 967 * Retrieves the binary representation of the subFinal element for this 968 * matched values filter, if available. 969 * 970 * @return The binary representation of the subFinal element for this matched 971 * values filter, or {@code null} if there is none. 972 */ 973 public byte[] getSubFinalValueBytes() 974 { 975 if (subFinalValue == null) 976 { 977 return null; 978 } 979 else 980 { 981 return subFinalValue.getValue(); 982 } 983 } 984 985 986 987 /** 988 * Retrieves the raw subFinal element for this matched values filter, if 989 * available. 990 * 991 * @return The raw subFinal element for this matched values filter, or 992 * {@code null} if there is none. 993 */ 994 public ASN1OctetString getRawSubFinalValue() 995 { 996 return subFinalValue; 997 } 998 999 1000 1001 /** 1002 * Retrieves the matching rule ID for this matched values filter, if 1003 * available. 1004 * 1005 * @return The matching rule ID for this matched values filter, or 1006 * {@code null} if there is none. 1007 */ 1008 public String getMatchingRuleID() 1009 { 1010 return matchingRuleID; 1011 } 1012 1013 1014 1015 /** 1016 * Encodes this matched values filter for use in the matched values control. 1017 * 1018 * @return The ASN.1 element containing the encoded representation of this 1019 * matched values filter. 1020 */ 1021 public ASN1Element encode() 1022 { 1023 switch (matchType) 1024 { 1025 case MATCH_TYPE_EQUALITY: 1026 case MATCH_TYPE_GREATER_OR_EQUAL: 1027 case MATCH_TYPE_LESS_OR_EQUAL: 1028 case MATCH_TYPE_APPROXIMATE: 1029 ASN1Element[] elements = 1030 { 1031 new ASN1OctetString(attributeType), 1032 assertionValue 1033 }; 1034 return new ASN1Sequence(matchType, elements); 1035 1036 case MATCH_TYPE_SUBSTRINGS: 1037 final ArrayList<ASN1Element> subElements = new ArrayList<>(3); 1038 if (subInitialValue != null) 1039 { 1040 subElements.add(subInitialValue); 1041 } 1042 1043 if (subAnyValues.length > 0) 1044 { 1045 subElements.addAll(Arrays.asList(subAnyValues)); 1046 } 1047 1048 if (subFinalValue != null) 1049 { 1050 subElements.add(subFinalValue); 1051 } 1052 1053 elements = new ASN1Element[] 1054 { 1055 new ASN1OctetString(attributeType), 1056 new ASN1Sequence(subElements) 1057 }; 1058 return new ASN1Sequence(matchType, elements); 1059 1060 case MATCH_TYPE_PRESENT: 1061 return new ASN1OctetString(matchType, attributeType); 1062 1063 case MATCH_TYPE_EXTENSIBLE: 1064 final ArrayList<ASN1Element> extElements = new ArrayList<>(3); 1065 if (attributeType != null) 1066 { 1067 extElements.add(new ASN1OctetString(EXTENSIBLE_TYPE_ATTRIBUTE_NAME, 1068 attributeType)); 1069 } 1070 1071 if (matchingRuleID != null) 1072 { 1073 extElements.add(new ASN1OctetString(EXTENSIBLE_TYPE_MATCHING_RULE_ID, 1074 matchingRuleID)); 1075 } 1076 1077 extElements.add(assertionValue); 1078 return new ASN1Sequence(matchType, extElements); 1079 1080 default: 1081 // This should never happen. 1082 return null; 1083 } 1084 } 1085 1086 1087 1088 /** 1089 * Decodes the provided ASN.1 element as a matched values filter. 1090 * 1091 * @param element The ASN.1 element to decode as a matched values filter. 1092 * 1093 * @return The decoded matched values filter. 1094 * 1095 * @throws LDAPException If the provided ASN.1 element cannot be decoded as 1096 * a matched values filter. 1097 */ 1098 public static MatchedValuesFilter decode(final ASN1Element element) 1099 throws LDAPException 1100 { 1101 ASN1OctetString assertionValue = null; 1102 ASN1OctetString subInitialValue = null; 1103 ASN1OctetString subFinalValue = null; 1104 ASN1OctetString[] subAnyValues = NO_SUB_ANY; 1105 final byte matchType = element.getType(); 1106 String attributeType = null; 1107 String matchingRuleID = null; 1108 1109 switch (matchType) 1110 { 1111 case MATCH_TYPE_EQUALITY: 1112 case MATCH_TYPE_GREATER_OR_EQUAL: 1113 case MATCH_TYPE_LESS_OR_EQUAL: 1114 case MATCH_TYPE_APPROXIMATE: 1115 try 1116 { 1117 final ASN1Element[] elements = 1118 ASN1Sequence.decodeAsSequence(element).elements(); 1119 attributeType = 1120 ASN1OctetString.decodeAsOctetString(elements[0]).stringValue(); 1121 assertionValue = 1122 ASN1OctetString.decodeAsOctetString(elements[1]); 1123 } 1124 catch (final Exception e) 1125 { 1126 Debug.debugException(e); 1127 throw new LDAPException(ResultCode.DECODING_ERROR, 1128 ERR_MV_FILTER_NOT_AVA.get(e), e); 1129 } 1130 break; 1131 1132 case MATCH_TYPE_SUBSTRINGS: 1133 try 1134 { 1135 final ASN1Element[] elements = 1136 ASN1Sequence.decodeAsSequence(element).elements(); 1137 attributeType = 1138 ASN1OctetString.decodeAsOctetString(elements[0]).stringValue(); 1139 1140 ArrayList<ASN1OctetString> subAnyList = null; 1141 final ASN1Element[] subElements = 1142 ASN1Sequence.decodeAsSequence(elements[1]).elements(); 1143 for (final ASN1Element e : subElements) 1144 { 1145 switch (e.getType()) 1146 { 1147 case SUBSTRING_TYPE_SUBINITIAL: 1148 if (subInitialValue == null) 1149 { 1150 subInitialValue = ASN1OctetString.decodeAsOctetString(e); 1151 } 1152 else 1153 { 1154 throw new LDAPException(ResultCode.DECODING_ERROR, 1155 ERR_MV_FILTER_MULTIPLE_SUBINITIAL.get()); 1156 } 1157 break; 1158 1159 case SUBSTRING_TYPE_SUBANY: 1160 if (subAnyList == null) 1161 { 1162 subAnyList = new ArrayList<>(subElements.length); 1163 } 1164 subAnyList.add(ASN1OctetString.decodeAsOctetString(e)); 1165 break; 1166 1167 case SUBSTRING_TYPE_SUBFINAL: 1168 if (subFinalValue == null) 1169 { 1170 subFinalValue = ASN1OctetString.decodeAsOctetString(e); 1171 } 1172 else 1173 { 1174 throw new LDAPException(ResultCode.DECODING_ERROR, 1175 ERR_MV_FILTER_MULTIPLE_SUBFINAL.get()); 1176 } 1177 break; 1178 1179 default: 1180 throw new LDAPException(ResultCode.DECODING_ERROR, 1181 ERR_MV_FILTER_INVALID_SUB_TYPE.get( 1182 StaticUtils.toHex(e.getType()))); 1183 } 1184 } 1185 1186 if (subAnyList != null) 1187 { 1188 subAnyValues = 1189 subAnyList.toArray(new ASN1OctetString[subAnyList.size()]); 1190 } 1191 } 1192 catch (final LDAPException le) 1193 { 1194 Debug.debugException(le); 1195 throw le; 1196 } 1197 catch (final Exception e) 1198 { 1199 Debug.debugException(e); 1200 throw new LDAPException(ResultCode.DECODING_ERROR, 1201 ERR_MV_FILTER_CANNOT_DECODE_SUBSTRING.get(e), e); 1202 } 1203 1204 if ((subInitialValue == null) && (subAnyValues.length == 0) && 1205 (subFinalValue == null)) 1206 { 1207 throw new LDAPException(ResultCode.DECODING_ERROR, 1208 ERR_MV_FILTER_NO_SUBSTRING_ELEMENTS.get()); 1209 } 1210 break; 1211 1212 case MATCH_TYPE_PRESENT: 1213 attributeType = 1214 ASN1OctetString.decodeAsOctetString(element).stringValue(); 1215 break; 1216 1217 case MATCH_TYPE_EXTENSIBLE: 1218 try 1219 { 1220 final ASN1Element[] elements = 1221 ASN1Sequence.decodeAsSequence(element).elements(); 1222 for (final ASN1Element e : elements) 1223 { 1224 switch (e.getType()) 1225 { 1226 case EXTENSIBLE_TYPE_ATTRIBUTE_NAME: 1227 if (attributeType == null) 1228 { 1229 attributeType = 1230 ASN1OctetString.decodeAsOctetString(e).stringValue(); 1231 } 1232 else 1233 { 1234 throw new LDAPException(ResultCode.DECODING_ERROR, 1235 ERR_MV_FILTER_EXT_MULTIPLE_AT.get()); 1236 } 1237 break; 1238 1239 case EXTENSIBLE_TYPE_MATCHING_RULE_ID: 1240 if (matchingRuleID == null) 1241 { 1242 matchingRuleID = 1243 ASN1OctetString.decodeAsOctetString(e).stringValue(); 1244 } 1245 else 1246 { 1247 throw new LDAPException(ResultCode.DECODING_ERROR, 1248 ERR_MV_FILTER_MULTIPLE_MRID.get()); 1249 } 1250 break; 1251 1252 case EXTENSIBLE_TYPE_MATCH_VALUE: 1253 if (assertionValue == null) 1254 { 1255 assertionValue = 1256 ASN1OctetString.decodeAsOctetString(e); 1257 } 1258 else 1259 { 1260 throw new LDAPException(ResultCode.DECODING_ERROR, 1261 ERR_MV_FILTER_EXT_MULTIPLE_VALUE.get()); 1262 } 1263 break; 1264 1265 default: 1266 throw new LDAPException(ResultCode.DECODING_ERROR, 1267 ERR_MV_FILTER_EXT_INVALID_TYPE.get( 1268 StaticUtils.toHex(e.getType()))); 1269 } 1270 } 1271 } 1272 catch (final LDAPException le) 1273 { 1274 Debug.debugException(le); 1275 throw le; 1276 } 1277 catch (final Exception e) 1278 { 1279 Debug.debugException(e); 1280 throw new LDAPException(ResultCode.DECODING_ERROR, 1281 ERR_MV_FILTER_EXT_NOT_SEQUENCE.get(e), e); 1282 } 1283 1284 if ((attributeType == null) && (matchingRuleID == null)) 1285 { 1286 throw new LDAPException(ResultCode.DECODING_ERROR, 1287 ERR_MV_FILTER_NO_ATTR_OR_MRID.get()); 1288 } 1289 1290 if (assertionValue == null) 1291 { 1292 throw new LDAPException(ResultCode.DECODING_ERROR, 1293 ERR_MV_FILTER_EXT_NO_VALUE.get()); 1294 } 1295 break; 1296 1297 default: 1298 throw new LDAPException(ResultCode.DECODING_ERROR, 1299 ERR_MV_FILTER_INVALID_TYPE.get( 1300 StaticUtils.toHex(matchType))); 1301 } 1302 1303 return new MatchedValuesFilter(matchType, attributeType, assertionValue, 1304 subInitialValue, subAnyValues, subFinalValue, 1305 matchingRuleID); 1306 } 1307 1308 1309 1310 /** 1311 * Creates a search filter that is the equivalent of this matched values 1312 * filter. 1313 * 1314 * @return A search filter that is the equivalent of this matched values 1315 * filter. 1316 */ 1317 public Filter toFilter() 1318 { 1319 switch (matchType) 1320 { 1321 case MATCH_TYPE_EQUALITY: 1322 return Filter.createEqualityFilter(attributeType, 1323 assertionValue.getValue()); 1324 1325 case MATCH_TYPE_SUBSTRINGS: 1326 return Filter.createSubstringFilter(attributeType, 1327 getSubInitialValueBytes(), getSubAnyValueBytes(), 1328 getSubFinalValueBytes()); 1329 1330 case MATCH_TYPE_GREATER_OR_EQUAL: 1331 return Filter.createGreaterOrEqualFilter(attributeType, 1332 assertionValue.getValue()); 1333 1334 case MATCH_TYPE_LESS_OR_EQUAL: 1335 return Filter.createLessOrEqualFilter(attributeType, 1336 assertionValue.getValue()); 1337 1338 case MATCH_TYPE_PRESENT: 1339 return Filter.createPresenceFilter(attributeType); 1340 1341 case MATCH_TYPE_APPROXIMATE: 1342 return Filter.createApproximateMatchFilter(attributeType, 1343 assertionValue.getValue()); 1344 1345 case MATCH_TYPE_EXTENSIBLE: 1346 return Filter.createExtensibleMatchFilter(attributeType, matchingRuleID, 1347 false, assertionValue.getValue()); 1348 1349 default: 1350 // This should never happen. 1351 return null; 1352 } 1353 } 1354 1355 1356 1357 /** 1358 * Retrieves a string representation of this matched values filter. 1359 * 1360 * @return A string representation of this matched values filter. 1361 */ 1362 @Override() 1363 public String toString() 1364 { 1365 final StringBuilder buffer = new StringBuilder(); 1366 toString(buffer); 1367 return buffer.toString(); 1368 } 1369 1370 1371 1372 /** 1373 * Appends a string representation of this matched values filter to the 1374 * provided buffer. 1375 * 1376 * @param buffer The buffer to which to append the string representation of 1377 * this matched values filter. 1378 */ 1379 public void toString(final StringBuilder buffer) 1380 { 1381 buffer.append('('); 1382 1383 switch (matchType) 1384 { 1385 case MATCH_TYPE_EQUALITY: 1386 buffer.append(attributeType); 1387 buffer.append('='); 1388 buffer.append(assertionValue.stringValue()); 1389 break; 1390 1391 case MATCH_TYPE_SUBSTRINGS: 1392 buffer.append(attributeType); 1393 buffer.append('='); 1394 1395 if (subInitialValue != null) 1396 { 1397 buffer.append(subInitialValue.stringValue()); 1398 } 1399 1400 for (final ASN1OctetString s : subAnyValues) 1401 { 1402 buffer.append('*'); 1403 buffer.append(s.stringValue()); 1404 } 1405 1406 buffer.append('*'); 1407 if (subFinalValue != null) 1408 { 1409 buffer.append(subFinalValue.stringValue()); 1410 } 1411 break; 1412 1413 case MATCH_TYPE_GREATER_OR_EQUAL: 1414 buffer.append(attributeType); 1415 buffer.append(">="); 1416 buffer.append(assertionValue.stringValue()); 1417 break; 1418 1419 case MATCH_TYPE_LESS_OR_EQUAL: 1420 buffer.append(attributeType); 1421 buffer.append("<="); 1422 buffer.append(assertionValue.stringValue()); 1423 break; 1424 1425 case MATCH_TYPE_PRESENT: 1426 buffer.append(attributeType); 1427 buffer.append("=*"); 1428 break; 1429 1430 case MATCH_TYPE_APPROXIMATE: 1431 buffer.append(attributeType); 1432 buffer.append("~="); 1433 buffer.append(assertionValue.stringValue()); 1434 break; 1435 1436 case MATCH_TYPE_EXTENSIBLE: 1437 if (attributeType != null) 1438 { 1439 buffer.append(attributeType); 1440 } 1441 1442 if (matchingRuleID != null) 1443 { 1444 buffer.append(':'); 1445 buffer.append(matchingRuleID); 1446 } 1447 1448 buffer.append(":="); 1449 buffer.append(assertionValue.stringValue()); 1450 break; 1451 } 1452 1453 buffer.append(')'); 1454 } 1455}