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