001/* 002 * The contents of this file are subject to the terms of the Common Development and 003 * Distribution License (the License). You may not use this file except in compliance with the 004 * License. 005 * 006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 007 * specific language governing permission and limitations under the License. 008 * 009 * When distributing Covered Software, include this CDDL Header Notice in each file and include 010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 011 * Header, with the fields enclosed by brackets [] replaced by your own identifying 012 * information: "Portions Copyright [year] [name of copyright owner]". 013 * 014 * Copyright 2006-2009 Sun Microsystems, Inc. 015 * Portions Copyright 2013-2015 ForgeRock AS. 016 */ 017package org.opends.server.types; 018 019import org.forgerock.opendj.ldap.ByteString; 020import org.forgerock.i18n.LocalizableMessage; 021 022 023 024import java.util.ArrayList; 025import java.io.IOException; 026 027import org.forgerock.i18n.slf4j.LocalizedLogger; 028import org.forgerock.opendj.io.*; 029import org.opends.server.protocols.ldap.LDAPFilter; 030 031import static org.opends.messages.ProtocolMessages.*; 032import static org.opends.server.protocols.ldap.LDAPConstants.*; 033import static org.opends.server.protocols.ldap.LDAPResultCode.*; 034import static org.opends.server.util.StaticUtils.*; 035 036 037 038/** 039 * This class defines the data structures and methods to use when 040 * interacting with a raw search filter, which defines a set of 041 * criteria for locating entries in a search request. 042 */ 043@org.opends.server.types.PublicAPI( 044 stability=org.opends.server.types.StabilityLevel.UNCOMMITTED, 045 mayInstantiate=true, 046 mayExtend=false, 047 mayInvoke=true) 048public abstract class RawFilter 049{ 050 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 051 052 /** 053 * Creates a new LDAP filter from the provided filter string. 054 * 055 * @param filterString The filter string to use to create this raw 056 * filter. 057 * 058 * @return The raw filter decoded from the provided filter string. 059 * 060 * @throws LDAPException If the provied filter string could not be 061 * decoded as a raw filter. 062 */ 063 public static RawFilter create(String filterString) 064 throws LDAPException 065 { 066 return LDAPFilter.decode(filterString); 067 } 068 069 070 071 /** 072 * Creates a new LDAP filter from the provided search filter. 073 * 074 * @param filter The search filter to use to create this raw 075 * filter. 076 * 077 * @return The constructed raw filter. 078 */ 079 public static RawFilter create(SearchFilter filter) 080 { 081 return new LDAPFilter(filter); 082 } 083 084 085 086 /** 087 * Creates a new AND search filter with the provided filter 088 * components. 089 * 090 * @param filterComponents The filter components for this AND 091 * filter. 092 * 093 * @return The AND search filter with the provided filter 094 * components. 095 */ 096 public static LDAPFilter createANDFilter(ArrayList<RawFilter> 097 filterComponents) 098 { 099 return new LDAPFilter(FilterType.AND, filterComponents, null, 100 null, null, null, null, null, null, false); 101 } 102 103 104 105 /** 106 * Creates a new OR search filter with the provided filter 107 * components. 108 * 109 * @param filterComponents The filter components for this OR 110 * filter. 111 * 112 * @return The OR search filter with the provided filter 113 * components. 114 */ 115 public static LDAPFilter createORFilter(ArrayList<RawFilter> 116 filterComponents) 117 { 118 return new LDAPFilter(FilterType.OR, filterComponents, null, null, 119 null, null, null, null, null, false); 120 } 121 122 123 124 /** 125 * Creates a new NOT search filter with the provided filter 126 * component. 127 * 128 * @param notComponent The filter component for this NOT filter. 129 * 130 * @return The NOT search filter with the provided filter 131 * component. 132 */ 133 public static LDAPFilter createNOTFilter(RawFilter notComponent) 134 { 135 return new LDAPFilter(FilterType.NOT, null, notComponent, null, 136 null, null, null, null, null, false); 137 } 138 139 140 141 /** 142 * Creates a new equality search filter with the provided 143 * information. 144 * 145 * @param attributeType The attribute type for this equality 146 * filter. 147 * @param assertionValue The assertion value for this equality 148 * filter. 149 * 150 * @return The constructed equality search filter. 151 */ 152 public static LDAPFilter createEqualityFilter(String attributeType, 153 ByteString assertionValue) 154 { 155 return new LDAPFilter(FilterType.EQUALITY, null, null, 156 attributeType, assertionValue, null, null, 157 null, null, false); 158 } 159 160 161 162 /** 163 * Creates a new substring search filter with the provided 164 * information. 165 * 166 * @param attributeType The attribute type for this substring 167 * filter. 168 * @param subInitialElement The subInitial element for this 169 * substring filter. 170 * @param subAnyElements The subAny elements for this substring 171 * filter. 172 * @param subFinalElement The subFinal element for this 173 * substring filter. 174 * 175 * @return The constructed substring search filter. 176 */ 177 public static LDAPFilter createSubstringFilter(String attributeType, 178 ByteString subInitialElement, 179 ArrayList<ByteString> subAnyElements, 180 ByteString subFinalElement) 181 { 182 return new LDAPFilter(FilterType.SUBSTRING, null, null, 183 attributeType, null, subInitialElement, 184 subAnyElements, subFinalElement, null, 185 false); 186 } 187 188 189 190 /** 191 * Creates a new greater or equal search filter with the provided 192 * information. 193 * 194 * @param attributeType The attribute type for this greater or 195 * equal filter. 196 * @param assertionValue The assertion value for this greater or 197 * equal filter. 198 * 199 * @return The constructed greater or equal search filter. 200 */ 201 public static LDAPFilter createGreaterOrEqualFilter( 202 String attributeType, 203 ByteString assertionValue) 204 { 205 return new LDAPFilter(FilterType.GREATER_OR_EQUAL, null, null, 206 attributeType, assertionValue, null, null, 207 null, null, false); 208 } 209 210 211 212 /** 213 * Creates a new less or equal search filter with the provided 214 * information. 215 * 216 * @param attributeType The attribute type for this less or equal 217 * filter. 218 * @param assertionValue The assertion value for this less or 219 * equal filter. 220 * 221 * @return The constructed less or equal search filter. 222 */ 223 public static LDAPFilter createLessOrEqualFilter( 224 String attributeType, 225 ByteString assertionValue) 226 { 227 return new LDAPFilter(FilterType.LESS_OR_EQUAL, null, null, 228 attributeType, assertionValue, null, null, 229 null, null, false); 230 } 231 232 233 234 /** 235 * Creates a new presence search filter with the provided attribute 236 * type. 237 * 238 * @param attributeType The attribute type for this presence 239 * filter. 240 * 241 * @return The constructed presence search filter. 242 */ 243 public static LDAPFilter createPresenceFilter(String attributeType) 244 { 245 return new LDAPFilter(FilterType.PRESENT, null, null, 246 attributeType, null, null, null, null, null, 247 false); 248 } 249 250 251 252 /** 253 * Creates a new approximate search filter with the provided 254 * information. 255 * 256 * @param attributeType The attribute type for this approximate 257 * filter. 258 * @param assertionValue The assertion value for this approximate 259 * filter. 260 * 261 * @return The constructed approximate search filter. 262 */ 263 public static LDAPFilter createApproximateFilter( 264 String attributeType, 265 ByteString assertionValue) 266 { 267 return new LDAPFilter(FilterType.APPROXIMATE_MATCH, null, null, 268 attributeType, assertionValue, null, null, 269 null, null, false); 270 } 271 272 273 274 /** 275 * Creates a new extensible matching search filter with the provided 276 * information. 277 * 278 * @param matchingRuleID The matching rule ID for this extensible 279 * filter. 280 * @param attributeType The attribute type for this extensible 281 * filter. 282 * @param assertionValue The assertion value for this extensible 283 * filter. 284 * @param dnAttributes The dnAttributes flag for this extensible 285 * filter. 286 * 287 * @return The constructed extensible matching search filter. 288 */ 289 public static LDAPFilter createExtensibleFilter( 290 String matchingRuleID, 291 String attributeType, 292 ByteString assertionValue, 293 boolean dnAttributes) 294 { 295 return new LDAPFilter(FilterType.EXTENSIBLE_MATCH, null, null, 296 attributeType, assertionValue, null, null, 297 null, matchingRuleID, dnAttributes); 298 } 299 300 301 302 /** 303 * Retrieves the filter type for this search filter. 304 * 305 * @return The filter type for this search filter. 306 */ 307 public abstract FilterType getFilterType(); 308 309 310 311 /** 312 * Retrieves the set of subordinate filter components for AND or OR 313 * searches. The contents of the returned list may be altered by 314 * the caller. 315 * 316 * @return The set of subordinate filter components for AND and OR 317 * searches, or {@code null} if this is not an AND or OR 318 * search. 319 */ 320 public abstract ArrayList<RawFilter> getFilterComponents(); 321 322 323 324 /** 325 * Retrieves the subordinate filter component for NOT searches. 326 * 327 * @return The subordinate filter component for NOT searches, or 328 * {@code null} if this is not a NOT search. 329 */ 330 public abstract RawFilter getNOTComponent(); 331 332 333 334 /** 335 * Retrieves the attribute type for this search filter. This will 336 * not be applicable for AND, OR, or NOT filters. 337 * 338 * @return The attribute type for this search filter, or 339 * {@code null} if there is none. 340 */ 341 public abstract String getAttributeType(); 342 343 344 345 /** 346 * Retrieves the assertion value for this search filter. This will 347 * only be applicable for equality, greater or equal, less or equal, 348 * approximate, or extensible matching filters. 349 * 350 * @return The assertion value for this search filter, or 351 * {@code null} if there is none. 352 */ 353 public abstract ByteString getAssertionValue(); 354 355 356 357 /** 358 * Retrieves the subInitial component for this substring filter. 359 * This is only applicable for substring search filters, but even 360 * substring filters might not have a value for this component. 361 * 362 * @return The subInitial component for this substring filter, or 363 * {@code null} if there is none. 364 */ 365 public abstract ByteString getSubInitialElement(); 366 367 368 369 /** 370 * Retrieves the set of subAny elements for this substring filter. 371 * This is only applicable for substring search filters, and even 372 * then may be {@code null} or empty for some substring filters. 373 * 374 * @return The set of subAny elements for this substring filter, or 375 * {@code null} if there are none. 376 */ 377 public abstract ArrayList<ByteString> getSubAnyElements(); 378 379 380 381 /** 382 * Retrieves the subFinal element for this substring filter. This 383 * is not applicable for any other filter type, and may not be 384 * provided even for some substring filters. 385 * 386 * @return The subFinal element for this substring filter, or 387 * {@code null} if there is none. 388 */ 389 public abstract ByteString getSubFinalElement(); 390 391 392 393 /** 394 * Retrieves the matching rule ID for this extensible match filter. 395 * This is not applicable for any other type of filter and may not 396 * be included in some extensible matching filters. 397 * 398 * @return The matching rule ID for this extensible match filter, 399 * or {@code null} if there is none. 400 */ 401 public abstract String getMatchingRuleID(); 402 403 404 405 /** 406 * Retrieves the value of the DN attributes flag for this extensible 407 * match filter, which indicates whether to perform matching on the 408 * components of the DN. This does not apply for any other type of 409 * filter. 410 * 411 * @return The value of the DN attributes flag for this 412 * extensibleMatch filter. 413 */ 414 public abstract boolean getDNAttributes(); 415 416 /** 417 * Writes this protocol op to an ASN.1 output stream. 418 * 419 * @param stream The ASN.1 output stream to write to. 420 * @throws IOException If a problem occurs while writing to the 421 * stream. 422 */ 423 public void write(ASN1Writer stream) throws IOException 424 { 425 FilterType filterType = getFilterType(); 426 switch (filterType) 427 { 428 case AND: 429 case OR: 430 stream.writeStartSequence(filterType.getBERType()); 431 for(RawFilter f : getFilterComponents()) 432 { 433 f.write(stream); 434 } 435 stream.writeEndSequence(); 436 return; 437 case NOT: 438 stream.writeStartSequence(filterType.getBERType()); 439 getNOTComponent().write(stream); 440 stream.writeEndSequence(); 441 return; 442 case EQUALITY: 443 case GREATER_OR_EQUAL: 444 case LESS_OR_EQUAL: 445 case APPROXIMATE_MATCH: 446 stream.writeStartSequence(filterType.getBERType()); 447 stream.writeOctetString(getAttributeType()); 448 stream.writeOctetString(getAssertionValue()); 449 stream.writeEndSequence(); 450 return; 451 case SUBSTRING: 452 stream.writeStartSequence(filterType.getBERType()); 453 stream.writeOctetString(getAttributeType()); 454 455 stream.writeStartSequence(); 456 ByteString subInitialElement = getSubInitialElement(); 457 if (subInitialElement != null) 458 { 459 stream.writeOctetString(TYPE_SUBINITIAL, subInitialElement); 460 } 461 462 ArrayList<ByteString> subAnyElements = getSubAnyElements(); 463 if (subAnyElements != null && !subAnyElements.isEmpty()) 464 { 465 for (ByteString s : subAnyElements) 466 { 467 stream.writeOctetString(TYPE_SUBANY, s); 468 } 469 } 470 471 ByteString subFinalElement = getSubFinalElement(); 472 if (subFinalElement != null) 473 { 474 stream.writeOctetString(TYPE_SUBFINAL, subFinalElement); 475 } 476 stream.writeEndSequence(); 477 478 stream.writeEndSequence(); 479 return; 480 case PRESENT: 481 stream.writeOctetString(filterType.getBERType(), 482 getAttributeType()); 483 return; 484 case EXTENSIBLE_MATCH: 485 stream.writeStartSequence(filterType.getBERType()); 486 487 String matchingRuleID = getMatchingRuleID(); 488 if (matchingRuleID != null) 489 { 490 stream.writeOctetString(TYPE_MATCHING_RULE_ID, 491 matchingRuleID); 492 } 493 494 String attributeType = getAttributeType(); 495 if (attributeType != null) 496 { 497 stream.writeOctetString(TYPE_MATCHING_RULE_TYPE, 498 attributeType); 499 } 500 501 stream.writeOctetString(TYPE_MATCHING_RULE_VALUE, 502 getAssertionValue()); 503 504 if (getDNAttributes()) 505 { 506 stream.writeBoolean(TYPE_MATCHING_RULE_DN_ATTRIBUTES, true); 507 } 508 509 stream.writeEndSequence(); 510 return; 511 default: 512 if (logger.isTraceEnabled()) 513 { 514 logger.trace("Invalid search filter type: %s", 515 filterType); 516 } 517 } 518 } 519 520 /** 521 * Decodes the elements from the provided ASN.1 reader as a 522 * raw search filter. 523 * 524 * @param reader The ASN.1 reader. 525 * 526 * @return The decoded search filter. 527 * 528 * @throws LDAPException If the provided ASN.1 element cannot be 529 * decoded as a raw search filter. 530 */ 531 public static LDAPFilter decode(ASN1Reader reader) 532 throws LDAPException 533 { 534 byte type; 535 try 536 { 537 type = reader.peekType(); 538 } 539 catch(Exception e) 540 { 541 LocalizableMessage message = ERR_LDAP_FILTER_DECODE_NULL.get(); 542 throw new LDAPException(PROTOCOL_ERROR, message); 543 } 544 545 switch (type) 546 { 547 case TYPE_FILTER_AND: 548 case TYPE_FILTER_OR: 549 return decodeCompoundFilter(reader); 550 551 case TYPE_FILTER_NOT: 552 return decodeNotFilter(reader); 553 554 case TYPE_FILTER_EQUALITY: 555 case TYPE_FILTER_GREATER_OR_EQUAL: 556 case TYPE_FILTER_LESS_OR_EQUAL: 557 case TYPE_FILTER_APPROXIMATE: 558 return decodeAVAFilter(reader); 559 560 case TYPE_FILTER_SUBSTRING: 561 return decodeSubstringFilter(reader); 562 563 case TYPE_FILTER_PRESENCE: 564 return decodePresenceFilter(reader); 565 566 case TYPE_FILTER_EXTENSIBLE_MATCH: 567 return decodeExtensibleMatchFilter(reader); 568 569 default: 570 LocalizableMessage message = 571 ERR_LDAP_FILTER_DECODE_INVALID_TYPE.get(type); 572 throw new LDAPException(PROTOCOL_ERROR, message); 573 } 574 } 575 576 /** 577 * Decodes the elements from the provided ASN.1 reader as a compound 578 * filter (i.e. one that holds a set of subordinate filter 579 * components, like AND or OR filters). 580 * 581 * @param reader The ASN.1 reader. 582 * 583 * @return The decoded LDAP search filter. 584 * 585 * @throws LDAPException If a problem occurs while trying to 586 * decode the provided ASN.1 element as a 587 * raw search filter. 588 */ 589 private static LDAPFilter decodeCompoundFilter(ASN1Reader reader) 590 throws LDAPException 591 { 592 byte type; 593 try 594 { 595 type = reader.peekType(); 596 } 597 catch(Exception e) 598 { 599 LocalizableMessage message = ERR_LDAP_FILTER_DECODE_NULL.get(); 600 throw new LDAPException(PROTOCOL_ERROR, message); 601 } 602 603 FilterType filterType; 604 switch (type) 605 { 606 case TYPE_FILTER_AND: 607 filterType = FilterType.AND; 608 break; 609 case TYPE_FILTER_OR: 610 filterType = FilterType.OR; 611 break; 612 default: 613 // This should never happen. 614 if (logger.isTraceEnabled()) 615 { 616 logger.trace("Invalid filter type %x for a " + 617 "compound filter", type); 618 } 619 filterType = null; 620 } 621 622 ArrayList<RawFilter> filterComponents = new ArrayList<>(); 623 try 624 { 625 reader.readStartSequence(); 626 // Should have at least 1 filter 627 // could also be an absolute true/false filter 628 while (reader.hasNextElement()) 629 { 630 filterComponents.add(LDAPFilter.decode(reader)); 631 } 632 reader.readEndSequence(); 633 } 634 catch (LDAPException le) 635 { 636 throw le; 637 } 638 catch (Exception e) 639 { 640 logger.traceException(e); 641 642 LocalizableMessage message = ERR_LDAP_FILTER_DECODE_COMPOUND_COMPONENTS.get(e); 643 throw new LDAPException(PROTOCOL_ERROR, message, e); 644 } 645 646 return new LDAPFilter(filterType, filterComponents, null, null, 647 null, null, null, null, null, false); 648 } 649 650 /** 651 * Decodes the elements from the provided ASN.1 reader as a NOT 652 * filter. 653 * 654 * @param reader The ASN.1 reader. 655 * 656 * @return The decoded LDAP search filter. 657 * 658 * @throws LDAPException If a problem occurs while trying to 659 * decode the provided ASN.1 element as a 660 * raw search filter. 661 */ 662 private static LDAPFilter decodeNotFilter(ASN1Reader reader) 663 throws LDAPException 664 { 665 RawFilter notComponent; 666 try 667 { 668 reader.readStartSequence(); 669 notComponent = decode(reader); 670 reader.readEndSequence(); 671 } 672 catch (LDAPException le) 673 { 674 throw le; 675 } 676 catch (Exception e) 677 { 678 logger.traceException(e); 679 680 LocalizableMessage message = ERR_LDAP_FILTER_DECODE_NOT_COMPONENT.get(e); 681 throw new LDAPException(PROTOCOL_ERROR, message, e); 682 } 683 684 685 return new LDAPFilter(FilterType.NOT, null, notComponent, null, 686 null, null, null, null, null, false); 687 } 688 689 /** 690 * Decodes the elements from the provided ASN.1 read as as a filter 691 * containing an attribute type and an assertion value. This 692 * includes equality, greater or equal, less or equal, and 693 * approximate search filters. 694 * 695 * @param reader The ASN.1 reader. 696 * 697 * @return The decoded LDAP search filter. 698 * 699 * @throws LDAPException If a problem occurs while trying to 700 * decode the provided ASN.1 element as a 701 * raw search filter. 702 */ 703 private static LDAPFilter decodeAVAFilter(ASN1Reader reader) 704 throws LDAPException 705 { 706 byte type; 707 try 708 { 709 type = reader.peekType(); 710 } 711 catch(Exception e) 712 { 713 LocalizableMessage message = ERR_LDAP_FILTER_DECODE_NULL.get(); 714 throw new LDAPException(PROTOCOL_ERROR, message); 715 } 716 717 FilterType filterType; 718 switch (type) 719 { 720 case TYPE_FILTER_EQUALITY: 721 filterType = FilterType.EQUALITY; 722 break; 723 case TYPE_FILTER_GREATER_OR_EQUAL: 724 filterType = FilterType.GREATER_OR_EQUAL; 725 break; 726 case TYPE_FILTER_LESS_OR_EQUAL: 727 filterType = FilterType.LESS_OR_EQUAL; 728 break; 729 case TYPE_FILTER_APPROXIMATE: 730 filterType = FilterType.APPROXIMATE_MATCH; 731 break; 732 default: 733 // This should never happen. 734 if (logger.isTraceEnabled()) 735 { 736 logger.trace("Invalid filter type %x for a " + 737 "type-and-value filter", type); 738 } 739 filterType = null; 740 } 741 742 try 743 { 744 reader.readStartSequence(); 745 } 746 catch (Exception e) 747 { 748 logger.traceException(e); 749 750 LocalizableMessage message = ERR_LDAP_FILTER_DECODE_TV_SEQUENCE.get(e); 751 throw new LDAPException(PROTOCOL_ERROR, message, e); 752 } 753 754 String attributeType; 755 try 756 { 757 attributeType = reader.readOctetStringAsString(); 758 } 759 catch (Exception e) 760 { 761 logger.traceException(e); 762 763 LocalizableMessage message = ERR_LDAP_FILTER_DECODE_TV_TYPE.get(e); 764 throw new LDAPException(PROTOCOL_ERROR, message, e); 765 } 766 767 768 ByteString assertionValue; 769 try 770 { 771 assertionValue = reader.readOctetString(); 772 } 773 catch (Exception e) 774 { 775 logger.traceException(e); 776 777 LocalizableMessage message = ERR_LDAP_FILTER_DECODE_TV_VALUE.get(e); 778 throw new LDAPException(PROTOCOL_ERROR, message, e); 779 } 780 781 try 782 { 783 reader.readEndSequence(); 784 } 785 catch (Exception e) 786 { 787 logger.traceException(e); 788 789 LocalizableMessage message = ERR_LDAP_FILTER_DECODE_TV_SEQUENCE.get(e); 790 throw new LDAPException(PROTOCOL_ERROR, message, e); 791 } 792 793 794 return new LDAPFilter(filterType, null, null, attributeType, 795 assertionValue, null, null, null, null, 796 false); 797 } 798 799 /** 800 * Decodes the elements from the provided ASN.1 reader as a 801 * substring filter. 802 * 803 * @param reader The ASN.1 reader. 804 * 805 * @return The decoded LDAP search filter. 806 * 807 * @throws LDAPException If a problem occurs while trying to 808 * decode the provided ASN.1 element as a 809 * raw search filter. 810 */ 811 private static LDAPFilter decodeSubstringFilter(ASN1Reader reader) 812 throws LDAPException 813 { 814 try 815 { 816 reader.readStartSequence(); 817 } 818 catch (Exception e) 819 { 820 logger.traceException(e); 821 822 LocalizableMessage message = ERR_LDAP_FILTER_DECODE_SUBSTRING_SEQUENCE.get(e); 823 throw new LDAPException(PROTOCOL_ERROR, message, e); 824 } 825 826 827 String attributeType; 828 try 829 { 830 attributeType = reader.readOctetStringAsString(); 831 } 832 catch (Exception e) 833 { 834 logger.traceException(e); 835 836 LocalizableMessage message = ERR_LDAP_FILTER_DECODE_SUBSTRING_TYPE.get(e); 837 throw new LDAPException(PROTOCOL_ERROR, message, e); 838 } 839 840 try 841 { 842 reader.readStartSequence(); 843 } 844 catch (Exception e) 845 { 846 logger.traceException(e); 847 848 LocalizableMessage message = ERR_LDAP_FILTER_DECODE_SUBSTRING_ELEMENTS.get(e); 849 throw new LDAPException(PROTOCOL_ERROR, message, e); 850 } 851 852 853 try 854 { 855 // Make sure we have at least 1 substring 856 reader.peekType(); 857 } 858 catch (Exception e) 859 { 860 LocalizableMessage message = 861 ERR_LDAP_FILTER_DECODE_SUBSTRING_NO_SUBELEMENTS.get(); 862 throw new LDAPException(PROTOCOL_ERROR, message); 863 } 864 865 866 ByteString subInitialElement = null; 867 ByteString subFinalElement = null; 868 ArrayList<ByteString> subAnyElements = null; 869 try 870 { 871 if(reader.hasNextElement() && 872 reader.peekType() == TYPE_SUBINITIAL) 873 { 874 subInitialElement = reader.readOctetString(); 875 } 876 while(reader.hasNextElement() && 877 reader.peekType() == TYPE_SUBANY) 878 { 879 if(subAnyElements == null) 880 { 881 subAnyElements = new ArrayList<>(); 882 } 883 subAnyElements.add(reader.readOctetString()); 884 } 885 if(reader.hasNextElement() && 886 reader.peekType() == TYPE_SUBFINAL) 887 { 888 subFinalElement = reader.readOctetString(); 889 } 890 } 891 catch (Exception e) 892 { 893 logger.traceException(e); 894 895 LocalizableMessage message = ERR_LDAP_FILTER_DECODE_SUBSTRING_VALUES.get(e); 896 throw new LDAPException(PROTOCOL_ERROR, message, e); 897 } 898 899 try 900 { 901 reader.readEndSequence(); 902 } 903 catch (Exception e) 904 { 905 logger.traceException(e); 906 907 LocalizableMessage message = ERR_LDAP_FILTER_DECODE_SUBSTRING_ELEMENTS.get(e); 908 throw new LDAPException(PROTOCOL_ERROR, message, e); 909 } 910 911 try 912 { 913 reader.readEndSequence(); 914 } 915 catch (Exception e) 916 { 917 logger.traceException(e); 918 919 LocalizableMessage message = ERR_LDAP_FILTER_DECODE_SUBSTRING_SEQUENCE.get(e); 920 throw new LDAPException(PROTOCOL_ERROR, message, e); 921 } 922 923 return new LDAPFilter(FilterType.SUBSTRING, null, null, 924 attributeType, null, subInitialElement, 925 subAnyElements, subFinalElement, null, 926 false); 927 } 928 929 /** 930 * Decodes the elements from the provided ASN.1 reader as a 931 * presence filter. 932 * 933 * @param reader The ASN.1 reader. 934 * 935 * @return The decoded LDAP search filter. 936 * 937 * @throws LDAPException If a problem occurs while trying to 938 * decode the provided ASN.1 element as a 939 * raw search filter. 940 */ 941 private static LDAPFilter decodePresenceFilter(ASN1Reader reader) 942 throws LDAPException 943 { 944 String attributeType; 945 try 946 { 947 attributeType = reader.readOctetStringAsString(); 948 } 949 catch (Exception e) 950 { 951 logger.traceException(e); 952 953 LocalizableMessage message = ERR_LDAP_FILTER_DECODE_PRESENCE_TYPE.get(e); 954 throw new LDAPException(PROTOCOL_ERROR, message, e); 955 } 956 957 958 return new LDAPFilter(FilterType.PRESENT, null, null, 959 attributeType, null, null, null, null, null, 960 false); 961 } 962 963 /** 964 * Decodes the elements from the provided ASN.1 reader as an 965 * extensible match filter. 966 * 967 * @param reader The ASN.1 reader. 968 * 969 * @return The decoded LDAP search filter. 970 * 971 * @throws LDAPException If a problem occurs while trying to 972 * decode the provided ASN.1 element as a 973 * raw search filter. 974 */ 975 private static LDAPFilter decodeExtensibleMatchFilter( 976 ASN1Reader reader) throws LDAPException 977 { 978 try 979 { 980 reader.readStartSequence(); 981 } 982 catch (Exception e) 983 { 984 logger.traceException(e); 985 986 LocalizableMessage message = ERR_LDAP_FILTER_DECODE_EXTENSIBLE_SEQUENCE.get(e); 987 throw new LDAPException(PROTOCOL_ERROR, message, e); 988 } 989 990 991 ByteString assertionValue; 992 boolean dnAttributes = false; 993 String attributeType = null; 994 String matchingRuleID = null; 995 try 996 { 997 if(reader.peekType() == TYPE_MATCHING_RULE_ID) 998 { 999 matchingRuleID = reader.readOctetStringAsString(); 1000 } 1001 if(matchingRuleID == null || 1002 reader.peekType() == TYPE_MATCHING_RULE_TYPE) 1003 { 1004 attributeType = reader.readOctetStringAsString(); 1005 } 1006 assertionValue = reader.readOctetString(); 1007 if(reader.hasNextElement() && 1008 reader.peekType() == TYPE_MATCHING_RULE_DN_ATTRIBUTES) 1009 { 1010 dnAttributes = reader.readBoolean(); 1011 } 1012 } 1013 catch (Exception e) 1014 { 1015 logger.traceException(e); 1016 1017 LocalizableMessage message = ERR_LDAP_FILTER_DECODE_EXTENSIBLE_ELEMENTS.get(e); 1018 throw new LDAPException(PROTOCOL_ERROR, message, e); 1019 } 1020 1021 try 1022 { 1023 reader.readEndSequence(); 1024 } 1025 catch (Exception e) 1026 { 1027 logger.traceException(e); 1028 1029 LocalizableMessage message = ERR_LDAP_FILTER_DECODE_EXTENSIBLE_SEQUENCE.get(e); 1030 throw new LDAPException(PROTOCOL_ERROR, message, e); 1031 } 1032 1033 1034 return new LDAPFilter(FilterType.EXTENSIBLE_MATCH, null, null, 1035 attributeType, assertionValue, null, null, 1036 null, matchingRuleID, dnAttributes); 1037 } 1038 1039 1040 1041 /** 1042 * Converts this raw filter to a search filter that may be used by 1043 * the Directory Server's core processing. 1044 * 1045 * @return The generated search filter. 1046 * 1047 * @throws DirectoryException If a problem occurs while attempting 1048 * to construct the search filter. 1049 */ 1050 public abstract SearchFilter toSearchFilter() 1051 throws DirectoryException; 1052 1053 1054 1055 /** 1056 * Retrieves a string representation of this search filter. 1057 * 1058 * @return A string representation of this search filter. 1059 */ 1060 @Override 1061 public String toString() 1062 { 1063 StringBuilder buffer = new StringBuilder(); 1064 toString(buffer); 1065 return buffer.toString(); 1066 } 1067 1068 1069 1070 /** 1071 * Appends a string representation of this search filter to the 1072 * provided buffer. 1073 * 1074 * @param buffer The buffer to which the information should be 1075 * appended. 1076 */ 1077 public abstract void toString(StringBuilder buffer); 1078 1079 1080 1081 /** 1082 * Appends a properly-cleaned version of the provided value to the 1083 * given buffer so that it can be safely used in string 1084 * representations of this search filter. The formatting changes 1085 * that may be performed will be in compliance with the 1086 * specification in RFC 2254. 1087 * 1088 * @param buffer The buffer to which the "safe" version of the 1089 * value will be appended. 1090 * @param value The value to be appended to the buffer. 1091 */ 1092 public static void valueToFilterString(StringBuilder buffer, 1093 ByteString value) 1094 { 1095 if (value == null) 1096 { 1097 return; 1098 } 1099 1100 1101 // Get the binary representation of the value and iterate through 1102 // it to see if there are any unsafe characters. If there are, 1103 // then escape them and replace them with a two-digit hex 1104 // equivalent. 1105 buffer.ensureCapacity(buffer.length() + value.length()); 1106 for (int i = 0; i < value.length(); i++) 1107 { 1108 byte b = value.byteAt(i); 1109 if (((b & 0x7F) != b) || // Not 7-bit clean 1110 (b <= 0x1F) || // Below the printable character range 1111 (b == 0x28) || // Open parenthesis 1112 (b == 0x29) || // Close parenthesis 1113 (b == 0x2A) || // Asterisk 1114 (b == 0x5C) || // Backslash 1115 (b == 0x7F)) // Delete character 1116 { 1117 buffer.append("\\"); 1118 buffer.append(byteToHex(b)); 1119 } 1120 else 1121 { 1122 buffer.append((char) b); 1123 } 1124 } 1125 } 1126} 1127