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