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