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 legal-notices/CDDLv1_0.txt 010 * or http://forgerock.org/license/CDDLv1.0.html. 011 * See the License for the specific language governing permissions 012 * and limitations under the License. 013 * 014 * When distributing Covered Code, include this CDDL HEADER in each 015 * file and include the License file at legal-notices/CDDLv1_0.txt. 016 * If applicable, add the following below this CDDL HEADER, with the 017 * fields enclosed by brackets "[]" replaced with your own identifying 018 * information: 019 * Portions Copyright [yyyy] [name of copyright owner] 020 * 021 * CDDL HEADER END 022 * 023 * 024 * Copyright 2006-2010 Sun Microsystems, Inc. 025 * Portions Copyright 2013-2014 Manuel Gaupp 026 * Portions Copyright 2014-2015 ForgeRock AS 027 */ 028package org.opends.server.controls; 029 030import java.io.IOException; 031import java.util.ArrayList; 032import java.util.List; 033 034import org.forgerock.i18n.LocalizableMessage; 035import org.forgerock.i18n.slf4j.LocalizedLogger; 036import org.forgerock.opendj.io.ASN1Reader; 037import org.forgerock.opendj.io.ASN1Writer; 038import org.forgerock.opendj.ldap.Assertion; 039import org.forgerock.opendj.ldap.ByteString; 040import org.forgerock.opendj.ldap.DecodeException; 041import org.forgerock.opendj.ldap.schema.MatchingRule; 042import org.forgerock.util.Reject; 043import org.opends.server.core.DirectoryServer; 044import org.opends.server.protocols.ldap.LDAPResultCode; 045import org.opends.server.types.AttributeType; 046import org.opends.server.types.LDAPException; 047import org.opends.server.types.RawFilter; 048 049import static org.opends.messages.ProtocolMessages.*; 050import static org.opends.server.protocols.ldap.LDAPConstants.*; 051import static org.opends.server.util.StaticUtils.*; 052 053/** 054 * This class defines a filter that may be used in conjunction with the matched 055 * values control to indicate which particular values of a multivalued attribute 056 * should be returned. The matched values filter is essentially a subset of an 057 * LDAP search filter, lacking support for AND, OR, and NOT components, and 058 * lacking support for the dnAttributes component of extensible matching 059 * filters. 060 */ 061public class MatchedValuesFilter 062{ 063 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 064 065 /** The BER type associated with the equalityMatch filter type. */ 066 public static final byte EQUALITY_MATCH_TYPE = (byte) 0xA3; 067 /** The BER type associated with the substrings filter type. */ 068 public static final byte SUBSTRINGS_TYPE = (byte) 0xA4; 069 /** The BER type associated with the greaterOrEqual filter type. */ 070 public static final byte GREATER_OR_EQUAL_TYPE = (byte) 0xA5; 071 /** The BER type associated with the lessOrEqual filter type. */ 072 public static final byte LESS_OR_EQUAL_TYPE = (byte) 0xA6; 073 /** The BER type associated with the present filter type. */ 074 public static final byte PRESENT_TYPE = (byte) 0x87; 075 /** The BER type associated with the approxMatch filter type. */ 076 public static final byte APPROXIMATE_MATCH_TYPE = (byte) 0xA8; 077 /** The BER type associated with the extensibleMatch filter type. */ 078 public static final byte EXTENSIBLE_MATCH_TYPE = (byte) 0xA9; 079 080 /** The matching rule ID for this matched values filter. */ 081 private final String matchingRuleID; 082 /** Indicates whether the elements of this matched values filter have been fully decoded. */ 083 private boolean decoded; 084 /** The match type for this matched values filter. */ 085 private final byte matchType; 086 087 /** The raw, unprocessed attribute type for this matched values filter. */ 088 private final String rawAttributeType; 089 /** The processed attribute type for this matched values filter. */ 090 private AttributeType attributeType; 091 092 /** The matching rule for this matched values filter. */ 093 private MatchingRule matchingRule; 094 /** The equality matching rule for this matched values filter. */ 095 private MatchingRule equalityMatchingRule; 096 /** The ordering matching rule for this matched values filter. */ 097 private MatchingRule orderingMatchingRule; 098 /** The substring matching rule for this matched values filter. */ 099 private MatchingRule substringMatchingRule; 100 /** The approximate matching rule for this matched values filter. */ 101 private MatchingRule approximateMatchingRule; 102 103 /** The raw, unprocessed assertion value for this matched values filter. */ 104 private final ByteString rawAssertionValue; 105 /** The processed assertion value for this matched values filter. */ 106 private ByteString assertionValue; 107 /** The assertion created from substring matching rule using values of this filter. */ 108 private Assertion substringAssertion; 109 /** The subInitial value for this matched values filter. */ 110 private final ByteString subInitial; 111 /** The set of subAny values for this matched values filter. */ 112 private final List<ByteString> subAny; 113 /** The subFinal value for this matched values filter. */ 114 private final ByteString subFinal; 115 116 /** 117 * Creates a new matched values filter with the provided information. 118 * 119 * @param matchType The match type for this matched values filter. 120 * @param rawAttributeType The raw, unprocessed attribute type. 121 * @param rawAssertionValue The raw, unprocessed assertion value. 122 * @param subInitial The subInitial element. 123 * @param subAny The set of subAny elements. 124 * @param subFinal The subFinal element. 125 * @param matchingRuleID The matching rule ID. 126 */ 127 private MatchedValuesFilter(byte matchType, String rawAttributeType, 128 ByteString rawAssertionValue, 129 ByteString subInitial, List<ByteString> subAny, 130 ByteString subFinal, String matchingRuleID) 131 { 132 this.matchType = matchType; 133 this.rawAttributeType = rawAttributeType; 134 this.rawAssertionValue = rawAssertionValue; 135 this.subInitial = subInitial; 136 this.subAny = subAny; 137 this.subFinal = subFinal; 138 this.matchingRuleID = matchingRuleID; 139 } 140 141 142 143 /** 144 * Creates a new equalityMatch filter with the provided information. 145 * 146 * @param rawAttributeType The raw, unprocessed attribute type. 147 * @param rawAssertionValue The raw, unprocessed assertion value. 148 * 149 * @return The created equalityMatch filter. 150 */ 151 public static MatchedValuesFilter createEqualityFilter( 152 String rawAttributeType, 153 ByteString rawAssertionValue) 154 { 155 Reject.ifNull(rawAttributeType,rawAssertionValue); 156 157 return new MatchedValuesFilter(EQUALITY_MATCH_TYPE, rawAttributeType, 158 rawAssertionValue, null, null, null, null); 159 } 160 161 162 163 /** 164 * Creates a new equalityMatch filter with the provided information. 165 * 166 * @param attributeType The attribute type. 167 * @param assertionValue The assertion value. 168 * 169 * @return The created equalityMatch filter. 170 */ 171 public static MatchedValuesFilter createEqualityFilter( 172 AttributeType attributeType, 173 ByteString assertionValue) 174 { 175 Reject.ifNull(attributeType, assertionValue); 176 String rawAttributeType = attributeType.getNameOrOID(); 177 178 MatchedValuesFilter filter = 179 new MatchedValuesFilter(EQUALITY_MATCH_TYPE, rawAttributeType, 180 assertionValue, null, null, null, null); 181 filter.attributeType = attributeType; 182 filter.assertionValue = assertionValue; 183 184 return filter; 185 } 186 187 188 189 /** 190 * Creates a new substrings filter with the provided information. 191 * 192 * @param rawAttributeType The raw, unprocessed attribute type. 193 * @param subInitial The subInitial element. 194 * @param subAny The set of subAny elements. 195 * @param subFinal The subFinal element. 196 * 197 * @return The created substrings filter. 198 */ 199 public static MatchedValuesFilter createSubstringsFilter( 200 String rawAttributeType, 201 ByteString subInitial, 202 List<ByteString> subAny, 203 ByteString subFinal) 204 { 205 Reject.ifNull(rawAttributeType); 206 return new MatchedValuesFilter(SUBSTRINGS_TYPE, rawAttributeType, null, 207 subInitial, subAny, subFinal, null); 208 } 209 210 211 212 /** 213 * Creates a new substrings filter with the provided information. 214 * 215 * @param attributeType The raw, unprocessed attribute type. 216 * @param subInitial The subInitial element. 217 * @param subAny The set of subAny elements. 218 * @param subFinal The subFinal element. 219 * 220 * @return The created substrings filter. 221 */ 222 public static MatchedValuesFilter createSubstringsFilter( 223 AttributeType attributeType, 224 ByteString subInitial, 225 List<ByteString> subAny, 226 ByteString subFinal) 227 { 228 Reject.ifNull(attributeType); 229 String rawAttributeType = attributeType.getNameOrOID(); 230 231 MatchedValuesFilter filter = 232 new MatchedValuesFilter(SUBSTRINGS_TYPE, rawAttributeType, null, 233 subInitial, subAny, subFinal, null); 234 filter.attributeType = attributeType; 235 236 return filter; 237 } 238 239 240 241 /** 242 * Creates a new greaterOrEqual filter with the provided information. 243 * 244 * @param rawAttributeType The raw, unprocessed attribute type. 245 * @param rawAssertionValue The raw, unprocessed assertion value. 246 * 247 * @return The created greaterOrEqual filter. 248 */ 249 public static MatchedValuesFilter createGreaterOrEqualFilter( 250 String rawAttributeType, 251 ByteString rawAssertionValue) 252 { 253 Reject.ifNull(rawAttributeType, rawAssertionValue); 254 255 return new MatchedValuesFilter(GREATER_OR_EQUAL_TYPE, rawAttributeType, 256 rawAssertionValue, null, null, null, null); 257 } 258 259 260 261 /** 262 * Creates a new greaterOrEqual filter with the provided information. 263 * 264 * @param attributeType The attribute type. 265 * @param assertionValue The assertion value. 266 * 267 * @return The created greaterOrEqual filter. 268 */ 269 public static MatchedValuesFilter createGreaterOrEqualFilter( 270 AttributeType attributeType, 271 ByteString assertionValue) 272 { 273 Reject.ifNull(attributeType, assertionValue); 274 275 String rawAttributeType = attributeType.getNameOrOID(); 276 277 MatchedValuesFilter filter = 278 new MatchedValuesFilter(GREATER_OR_EQUAL_TYPE, rawAttributeType, 279 assertionValue, null, null, null, null); 280 filter.attributeType = attributeType; 281 filter.assertionValue = assertionValue; 282 283 return filter; 284 } 285 286 287 288 /** 289 * Creates a new lessOrEqual filter with the provided information. 290 * 291 * @param rawAttributeType The raw, unprocessed attribute type. 292 * @param rawAssertionValue The raw, unprocessed assertion value. 293 * 294 * @return The created lessOrEqual filter. 295 */ 296 public static MatchedValuesFilter createLessOrEqualFilter( 297 String rawAttributeType, 298 ByteString rawAssertionValue) 299 { 300 Reject.ifNull(rawAttributeType, rawAssertionValue); 301 return new MatchedValuesFilter(LESS_OR_EQUAL_TYPE, rawAttributeType, 302 rawAssertionValue, null, null, null, null); 303 } 304 305 306 307 /** 308 * Creates a new lessOrEqual filter with the provided information. 309 * 310 * @param attributeType The attribute type. 311 * @param assertionValue The assertion value. 312 * 313 * @return The created lessOrEqual filter. 314 */ 315 public static MatchedValuesFilter createLessOrEqualFilter( 316 AttributeType attributeType, 317 ByteString assertionValue) 318 { 319 Reject.ifNull(attributeType, assertionValue); 320 321 String rawAttributeType = attributeType.getNameOrOID(); 322 323 MatchedValuesFilter filter = 324 new MatchedValuesFilter(LESS_OR_EQUAL_TYPE, rawAttributeType, 325 assertionValue, null, null, null, null); 326 filter.attributeType = attributeType; 327 filter.assertionValue = assertionValue; 328 329 return filter; 330 } 331 332 333 334 /** 335 * Creates a new present filter with the provided information. 336 * 337 * @param rawAttributeType The raw, unprocessed attribute type. 338 * 339 * @return The created present filter. 340 */ 341 public static MatchedValuesFilter createPresentFilter(String rawAttributeType) 342 { 343 Reject.ifNull(rawAttributeType) ; 344 return new MatchedValuesFilter(PRESENT_TYPE, rawAttributeType, null, null, 345 null, null, null); 346 } 347 348 349 350 /** 351 * Creates a new present filter with the provided information. 352 * 353 * @param attributeType The attribute type. 354 * 355 * @return The created present filter. 356 */ 357 public static MatchedValuesFilter createPresentFilter( 358 AttributeType attributeType) 359 { 360 Reject.ifNull(attributeType); 361 String rawAttributeType = attributeType.getNameOrOID(); 362 363 MatchedValuesFilter filter = 364 new MatchedValuesFilter(PRESENT_TYPE, rawAttributeType, null, null, 365 null, null, null); 366 filter.attributeType = attributeType; 367 368 return filter; 369 } 370 371 372 373 /** 374 * Creates a new approxMatch filter with the provided information. 375 * 376 * @param rawAttributeType The raw, unprocessed attribute type. 377 * @param rawAssertionValue The raw, unprocessed assertion value. 378 * 379 * @return The created approxMatch filter. 380 */ 381 public static MatchedValuesFilter createApproximateFilter( 382 String rawAttributeType, 383 ByteString rawAssertionValue) 384 { 385 Reject.ifNull(rawAttributeType,rawAssertionValue); 386 387 return new MatchedValuesFilter(APPROXIMATE_MATCH_TYPE, rawAttributeType, 388 rawAssertionValue, null, null, null, null); 389 } 390 391 392 393 /** 394 * Creates a new approxMatch filter with the provided information. 395 * 396 * @param attributeType The attribute type. 397 * @param assertionValue The assertion value. 398 * 399 * @return The created approxMatch filter. 400 */ 401 public static MatchedValuesFilter createApproximateFilter( 402 AttributeType attributeType, 403 ByteString assertionValue) 404 { 405 Reject.ifNull(attributeType,assertionValue); 406 String rawAttributeType = attributeType.getNameOrOID(); 407 408 MatchedValuesFilter filter = 409 new MatchedValuesFilter(APPROXIMATE_MATCH_TYPE, rawAttributeType, 410 assertionValue, null, null, null, null); 411 filter.attributeType = attributeType; 412 filter.assertionValue = assertionValue; 413 414 return filter; 415 } 416 417 418 419 /** 420 * Creates a new extensibleMatch filter with the provided information. 421 * 422 * @param rawAttributeType The raw, unprocessed attribute type. 423 * @param matchingRuleID The matching rule ID. 424 * @param rawAssertionValue The raw, unprocessed assertion value. 425 * 426 * @return The created extensibleMatch filter. 427 */ 428 public static MatchedValuesFilter createExtensibleMatchFilter( 429 String rawAttributeType, 430 String matchingRuleID, 431 ByteString rawAssertionValue) 432 { 433 Reject.ifNull(rawAttributeType, matchingRuleID, rawAssertionValue); 434 return new MatchedValuesFilter(EXTENSIBLE_MATCH_TYPE, rawAttributeType, 435 rawAssertionValue, null, null, null, 436 matchingRuleID); 437 } 438 439 440 441 /** 442 * Creates a new extensibleMatch filter with the provided information. 443 * 444 * @param attributeType The attribute type. 445 * @param matchingRule The matching rule. 446 * @param assertionValue The assertion value. 447 * 448 * @return The created extensibleMatch filter. 449 */ 450 public static MatchedValuesFilter createExtensibleMatchFilter( 451 AttributeType attributeType, 452 MatchingRule matchingRule, 453 ByteString assertionValue) 454 { 455 Reject.ifNull(attributeType, matchingRule, assertionValue); 456 String rawAttributeType = attributeType.getNameOrOID(); 457 String matchingRuleID = matchingRule.getOID(); 458 459 MatchedValuesFilter filter = 460 new MatchedValuesFilter(EXTENSIBLE_MATCH_TYPE, rawAttributeType, 461 assertionValue, null, null, null, 462 matchingRuleID); 463 filter.attributeType = attributeType; 464 filter.assertionValue = assertionValue; 465 filter.matchingRule = matchingRule; 466 467 return filter; 468 } 469 470 471 472 /** 473 * Creates a new matched values filter from the provided LDAP filter. 474 * 475 * @param filter The LDAP filter to use for this matched values filter. 476 * 477 * @return The corresponding matched values filter. 478 * 479 * @throws LDAPException If the provided LDAP filter cannot be treated as a 480 * matched values filter. 481 */ 482 public static MatchedValuesFilter createFromLDAPFilter(RawFilter filter) 483 throws LDAPException 484 { 485 switch (filter.getFilterType()) 486 { 487 case AND: 488 case OR: 489 case NOT: 490 // These filter types cannot be used in a matched values filter. 491 LocalizableMessage message = ERR_MVFILTER_INVALID_LDAP_FILTER_TYPE.get( 492 filter, filter.getFilterType()); 493 throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message); 494 495 496 case EQUALITY: 497 return new MatchedValuesFilter(EQUALITY_MATCH_TYPE, 498 filter.getAttributeType(), 499 filter.getAssertionValue(), null, null, 500 null, null); 501 502 503 case SUBSTRING: 504 return new MatchedValuesFilter(SUBSTRINGS_TYPE, 505 filter.getAttributeType(), null, 506 filter.getSubInitialElement(), 507 filter.getSubAnyElements(), 508 filter.getSubFinalElement(), null); 509 510 511 case GREATER_OR_EQUAL: 512 return new MatchedValuesFilter(GREATER_OR_EQUAL_TYPE, 513 filter.getAttributeType(), 514 filter.getAssertionValue(), null, null, 515 null, null); 516 517 518 case LESS_OR_EQUAL: 519 return new MatchedValuesFilter(LESS_OR_EQUAL_TYPE, 520 filter.getAttributeType(), 521 filter.getAssertionValue(), null, null, 522 null, null); 523 524 525 case PRESENT: 526 return new MatchedValuesFilter(PRESENT_TYPE, filter.getAttributeType(), 527 null, null, null, null, null); 528 529 530 case APPROXIMATE_MATCH: 531 return new MatchedValuesFilter(APPROXIMATE_MATCH_TYPE, 532 filter.getAttributeType(), 533 filter.getAssertionValue(), null, null, 534 null, null); 535 536 537 case EXTENSIBLE_MATCH: 538 if (filter.getDNAttributes()) 539 { 540 // This cannot be represented in a matched values filter. 541 message = ERR_MVFILTER_INVALID_DN_ATTRIBUTES_FLAG.get(filter); 542 throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message); 543 } 544 else 545 { 546 return new MatchedValuesFilter(EXTENSIBLE_MATCH_TYPE, 547 filter.getAttributeType(), 548 filter.getAssertionValue(), null, null, 549 null, filter.getMatchingRuleID()); 550 } 551 552 553 default: 554 message = ERR_MVFILTER_INVALID_LDAP_FILTER_TYPE.get(filter, filter.getFilterType()); 555 throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message); 556 } 557 } 558 559 /** 560 * Encodes this matched values filter as an ASN.1 element. 561 * 562 * @param writer The ASN1Writer to use to encode this matched values filter. 563 * @throws IOException if an error occurs while encoding. 564 */ 565 public void encode(ASN1Writer writer) throws IOException 566 { 567 switch (matchType) 568 { 569 case EQUALITY_MATCH_TYPE: 570 case GREATER_OR_EQUAL_TYPE: 571 case LESS_OR_EQUAL_TYPE: 572 case APPROXIMATE_MATCH_TYPE: 573 // These will all be encoded in the same way. 574 writer.writeStartSequence(matchType); 575 writer.writeOctetString(rawAttributeType); 576 writer.writeOctetString(rawAssertionValue); 577 writer.writeEndSequence(); 578 return; 579 580 case SUBSTRINGS_TYPE: 581 writer.writeStartSequence(matchType); 582 writer.writeOctetString(rawAttributeType); 583 584 writer.writeStartSequence(); 585 if (subInitial != null) 586 { 587 writer.writeOctetString(TYPE_SUBINITIAL, subInitial); 588 } 589 590 if (subAny != null) 591 { 592 for (ByteString s : subAny) 593 { 594 writer.writeOctetString(TYPE_SUBANY, s); 595 } 596 } 597 598 if (subFinal != null) 599 { 600 writer.writeOctetString(TYPE_SUBFINAL, subFinal); 601 } 602 writer.writeEndSequence(); 603 604 writer.writeEndSequence(); 605 return; 606 607 case PRESENT_TYPE: 608 writer.writeOctetString(matchType, rawAttributeType); 609 return; 610 611 case EXTENSIBLE_MATCH_TYPE: 612 writer.writeStartSequence(matchType); 613 if (matchingRuleID != null) 614 { 615 writer.writeOctetString(TYPE_MATCHING_RULE_ID, matchingRuleID); 616 } 617 618 if (rawAttributeType != null) 619 { 620 writer.writeOctetString(TYPE_MATCHING_RULE_TYPE, rawAttributeType); 621 } 622 writer.writeOctetString(TYPE_MATCHING_RULE_VALUE, rawAssertionValue); 623 writer.writeEndSequence(); 624 return; 625 626 627 default: 628 } 629 } 630 631 /** 632 * Decodes the provided ASN.1 element as a matched values filter item. 633 * 634 * @param reader The ASN.1 reader. 635 * 636 * @return The decoded matched values filter. 637 * 638 * @throws LDAPException If a problem occurs while attempting to decode the 639 * filter item. 640 */ 641 public static MatchedValuesFilter decode(ASN1Reader reader) 642 throws LDAPException 643 { 644 byte type; 645 try 646 { 647 type = reader.peekType(); 648 } 649 catch(Exception e) 650 { 651 // TODO: Need a better message. 652 throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, 653 ERR_MVFILTER_INVALID_ELEMENT_TYPE.get(e)); 654 } 655 656 switch (type) 657 { 658 case EQUALITY_MATCH_TYPE: 659 case GREATER_OR_EQUAL_TYPE: 660 case LESS_OR_EQUAL_TYPE: 661 case APPROXIMATE_MATCH_TYPE: 662 // These will all be decoded in the same manner. The element must be a 663 // sequence consisting of the attribute type and assertion value. 664 try 665 { 666 reader.readStartSequence(); 667 String rawAttributeType = reader.readOctetStringAsString(); 668 ByteString rawAssertionValue = reader.readOctetString(); 669 reader.readEndSequence(); 670 return new MatchedValuesFilter(type, rawAttributeType, 671 rawAssertionValue, null, null, null, null); 672 } 673 catch (Exception e) 674 { 675 logger.traceException(e); 676 677 LocalizableMessage message = 678 ERR_MVFILTER_CANNOT_DECODE_AVA.get(getExceptionMessage(e)); 679 throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message, e); 680 } 681 682 683 case SUBSTRINGS_TYPE: 684 // This must be a sequence of two elements, where the second is a 685 // sequence of substring types. 686 try 687 { 688 reader.readStartSequence(); 689 String rawAttributeType = reader.readOctetStringAsString(); 690 691 reader.readStartSequence(); 692 if(!reader.hasNextElement()) 693 { 694 LocalizableMessage message = ERR_MVFILTER_NO_SUBSTRING_ELEMENTS.get(); 695 throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message); 696 } 697 698 ByteString subInitial = null; 699 ArrayList<ByteString> subAny = null; 700 ByteString subFinal = null; 701 702 if(reader.hasNextElement() && 703 reader.peekType() == TYPE_SUBINITIAL) 704 { 705 subInitial = reader.readOctetString(); 706 } 707 while(reader.hasNextElement() && 708 reader.peekType() == TYPE_SUBANY) 709 { 710 if(subAny == null) 711 { 712 subAny = new ArrayList<>(); 713 } 714 subAny.add(reader.readOctetString()); 715 } 716 if(reader.hasNextElement() && 717 reader.peekType() == TYPE_SUBFINAL) 718 { 719 subFinal = reader.readOctetString(); 720 } 721 reader.readEndSequence(); 722 723 reader.readEndSequence(); 724 725 return new MatchedValuesFilter(type, rawAttributeType, 726 null, subInitial, subAny, subFinal, null); 727 } 728 catch (LDAPException le) 729 { 730 throw le; 731 } 732 catch (Exception e) 733 { 734 logger.traceException(e); 735 736 LocalizableMessage message = 737 ERR_MVFILTER_CANNOT_DECODE_SUBSTRINGS.get(getExceptionMessage(e)); 738 throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message, e); 739 } 740 741 742 case PRESENT_TYPE: 743 // The element must be an ASN.1 octet string holding the attribute type. 744 try 745 { 746 String rawAttributeType = reader.readOctetStringAsString(); 747 748 return new MatchedValuesFilter(type, rawAttributeType, 749 null, null, null, null, null); 750 } 751 catch (Exception e) 752 { 753 logger.traceException(e); 754 755 LocalizableMessage message = ERR_MVFILTER_CANNOT_DECODE_PRESENT_TYPE.get( 756 getExceptionMessage(e)); 757 throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message, e); 758 } 759 760 761 case EXTENSIBLE_MATCH_TYPE: 762 // This must be a two or three element sequence with an assertion value 763 // as the last element and an attribute type and/or matching rule ID as 764 // the first element(s). 765 try 766 { 767 reader.readStartSequence(); 768 769 String rawAttributeType = null; 770 String matchingRuleID = null; 771 772 if(reader.peekType() == TYPE_MATCHING_RULE_ID) 773 { 774 matchingRuleID = reader.readOctetStringAsString(); 775 } 776 if(matchingRuleID == null || 777 reader.peekType() == TYPE_MATCHING_RULE_TYPE) 778 { 779 rawAttributeType = reader.readOctetStringAsString(); 780 } 781 ByteString rawAssertionValue = reader.readOctetString(); 782 reader.readEndSequence(); 783 784 return new MatchedValuesFilter(type, rawAttributeType, 785 rawAssertionValue, null, null, null, 786 matchingRuleID); 787 } 788 catch (Exception e) 789 { 790 logger.traceException(e); 791 792 LocalizableMessage message = ERR_MVFILTER_CANNOT_DECODE_EXTENSIBLE_MATCH.get( 793 getExceptionMessage(e)); 794 throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message, e); 795 } 796 797 798 default: 799 LocalizableMessage message = 800 ERR_MVFILTER_INVALID_ELEMENT_TYPE.get(byteToHex(type)); 801 throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message); 802 } 803 } 804 805 806 807 /** 808 * Retrieves the match type for this matched values filter. 809 * 810 * @return The match type for this matched values filter. 811 */ 812 public byte getMatchType() 813 { 814 return matchType; 815 } 816 817 818 819 /** 820 * Retrieves the raw, unprocessed attribute type for this matched values 821 * filter. 822 * 823 * @return The raw, unprocessed attribute type for this matched values 824 * filter, or <CODE>null</CODE> if there is none. 825 */ 826 public String getRawAttributeType() 827 { 828 return rawAttributeType; 829 } 830 831 832 /** 833 * Retrieves the attribute type for this matched values filter. 834 * 835 * @return The attribute type for this matched values filter, or 836 * <CODE>null</CODE> if there is none. 837 */ 838 public AttributeType getAttributeType() 839 { 840 if (attributeType == null && rawAttributeType != null) 841 { 842 String lowerName = toLowerCase(rawAttributeType); 843 attributeType = DirectoryServer.getAttributeTypeOrDefault(lowerName, rawAttributeType); 844 } 845 return attributeType; 846 } 847 848 849 /** 850 * Retrieves the raw, unprocessed assertion value for this matched values 851 * filter. 852 * 853 * @return The raw, unprocessed assertion value for this matched values 854 * filter, or <CODE>null</CODE> if there is none. 855 */ 856 public ByteString getRawAssertionValue() 857 { 858 return rawAssertionValue; 859 } 860 861 862 863 /** 864 * Retrieves the assertion value for this matched values filter. 865 * 866 * @return The assertion value for this matched values filter, or 867 * <CODE>null</CODE> if there is none. 868 */ 869 public ByteString getAssertionValue() 870 { 871 if (assertionValue == null && rawAssertionValue != null) 872 { 873 assertionValue = rawAssertionValue; 874 } 875 return assertionValue; 876 } 877 878 879 880 /** 881 * Retrieves the subInitial element for this matched values filter. 882 * 883 * @return The subInitial element for this matched values filter, or 884 * <CODE>null</CODE> if there is none. 885 */ 886 public ByteString getSubInitialElement() 887 { 888 return subInitial; 889 } 890 891 private Assertion getSubstringAssertion() { 892 if (substringAssertion == null) 893 { 894 try 895 { 896 MatchingRule rule = getSubstringMatchingRule(); 897 if (rule != null) 898 { 899 substringAssertion = rule.getSubstringAssertion(subInitial, subAny, subFinal); 900 } 901 } 902 catch (DecodeException e) 903 { 904 logger.traceException(e); 905 } 906 } 907 return substringAssertion; 908 } 909 910 911 912 /** 913 * Retrieves the set of subAny elements for this matched values filter. 914 * 915 * @return The set of subAny elements for this matched values filter. If 916 * there are none, then the return value may be either 917 * <CODE>null</CODE> or an empty list. 918 */ 919 public List<ByteString> getSubAnyElements() 920 { 921 return subAny; 922 } 923 924 /** 925 * Retrieves the subFinal element for this matched values filter. 926 * 927 * @return The subFinal element for this matched values filter, or 928 * <CODE>null</CODE> if there is none. 929 */ 930 public ByteString getSubFinalElement() 931 { 932 return subFinal; 933 } 934 935 /** 936 * Retrieves the matching rule ID for this matched values filter. 937 * 938 * @return The matching rule ID for this matched values filter, or 939 * <CODE>null</CODE> if there is none. 940 */ 941 public String getMatchingRuleID() 942 { 943 return matchingRuleID; 944 } 945 946 947 948 /** 949 * Retrieves the matching rule for this matched values filter. 950 * 951 * @return The matching rule for this matched values filter, or 952 * <CODE>null</CODE> if there is none. 953 */ 954 public MatchingRule getMatchingRule() 955 { 956 if (matchingRule == null && matchingRuleID != null) 957 { 958 matchingRule = DirectoryServer.getMatchingRule(toLowerCase(matchingRuleID)); 959 } 960 return matchingRule; 961 } 962 963 964 965 /** 966 * Retrieves the approximate matching rule that should be used for this 967 * matched values filter. 968 * 969 * @return The approximate matching rule that should be used for this matched 970 * values filter, or <CODE>null</CODE> if there is none. 971 */ 972 public MatchingRule getApproximateMatchingRule() 973 { 974 if (approximateMatchingRule == null) 975 { 976 AttributeType attrType = getAttributeType(); 977 if (attrType != null) 978 { 979 approximateMatchingRule = attrType.getApproximateMatchingRule(); 980 } 981 } 982 983 return approximateMatchingRule; 984 } 985 986 987 988 /** 989 * Retrieves the equality matching rule that should be used for this matched 990 * values filter. 991 * 992 * @return The equality matching rule that should be used for this matched 993 * values filter, or <CODE>null</CODE> if there is none. 994 */ 995 public MatchingRule getEqualityMatchingRule() 996 { 997 if (equalityMatchingRule == null) 998 { 999 AttributeType attrType = getAttributeType(); 1000 if (attrType != null) 1001 { 1002 equalityMatchingRule = attrType.getEqualityMatchingRule(); 1003 } 1004 } 1005 1006 return equalityMatchingRule; 1007 } 1008 1009 1010 1011 /** 1012 * Retrieves the ordering matching rule that should be used for this matched 1013 * values filter. 1014 * 1015 * @return The ordering matching rule that should be used for this matched 1016 * values filter, or <CODE>null</CODE> if there is none. 1017 */ 1018 public MatchingRule getOrderingMatchingRule() 1019 { 1020 if (orderingMatchingRule == null) 1021 { 1022 AttributeType attrType = getAttributeType(); 1023 if (attrType != null) 1024 { 1025 orderingMatchingRule = attrType.getOrderingMatchingRule(); 1026 } 1027 } 1028 1029 return orderingMatchingRule; 1030 } 1031 1032 1033 1034 /** 1035 * Retrieves the substring matching rule that should be used for this matched 1036 * values filter. 1037 * 1038 * @return The substring matching rule that should be used for this matched 1039 * values filter, or <CODE>null</CODE> if there is none. 1040 */ 1041 public MatchingRule getSubstringMatchingRule() 1042 { 1043 if (substringMatchingRule == null) 1044 { 1045 AttributeType attrType = getAttributeType(); 1046 if (attrType != null) 1047 { 1048 substringMatchingRule = attrType.getSubstringMatchingRule(); 1049 } 1050 } 1051 1052 return substringMatchingRule; 1053 } 1054 1055 1056 1057 /** 1058 * Decodes all components of the matched values filter so that they can be 1059 * referenced as member variables. 1060 */ 1061 private void fullyDecode() 1062 { 1063 if (! decoded) 1064 { 1065 getAttributeType(); 1066 getAssertionValue(); 1067 getSubstringAssertion(); 1068 getMatchingRule(); 1069 getApproximateMatchingRule(); 1070 getEqualityMatchingRule(); 1071 getOrderingMatchingRule(); 1072 getSubstringMatchingRule(); 1073 decoded = true; 1074 } 1075 } 1076 1077 1078 1079 /** 1080 * Indicates whether the specified attribute value matches the criteria 1081 * defined in this matched values filter. 1082 * 1083 * @param type The attribute type with which the provided value is 1084 * associated. 1085 * @param value The attribute value for which to make the determination. 1086 * 1087 * @return <CODE>true</CODE> if the specified attribute value matches the 1088 * criteria defined in this matched values filter, or 1089 * <CODE>false</CODE> if not. 1090 */ 1091 public boolean valueMatches(AttributeType type, ByteString value) 1092 { 1093 fullyDecode(); 1094 1095 switch (matchType) 1096 { 1097 case EQUALITY_MATCH_TYPE: 1098 if (attributeType != null 1099 && attributeType.equals(type) 1100 && rawAssertionValue != null 1101 && value != null 1102 && equalityMatchingRule != null) 1103 { 1104 return matches(equalityMatchingRule, value, rawAssertionValue); 1105 } 1106 return false; 1107 1108 1109 case SUBSTRINGS_TYPE: 1110 if (attributeType != null 1111 && attributeType.equals(type) 1112 && substringAssertion != null) 1113 { 1114 try 1115 { 1116 return substringAssertion.matches(substringMatchingRule.normalizeAttributeValue(value)).toBoolean(); 1117 } 1118 catch (Exception e) 1119 { 1120 logger.traceException(e); 1121 } 1122 } 1123 return false; 1124 1125 1126 case GREATER_OR_EQUAL_TYPE: 1127 if (attributeType != null 1128 && attributeType.equals(type) 1129 && assertionValue != null 1130 && value != null 1131 && orderingMatchingRule != null) 1132 { 1133 try 1134 { 1135 ByteString normValue = orderingMatchingRule.normalizeAttributeValue(value); 1136 Assertion assertion = orderingMatchingRule.getGreaterOrEqualAssertion(assertionValue); 1137 return assertion.matches(normValue).toBoolean(); 1138 } 1139 catch (DecodeException e) 1140 { 1141 logger.traceException(e); 1142 } 1143 } 1144 return false; 1145 1146 1147 case LESS_OR_EQUAL_TYPE: 1148 if (attributeType != null 1149 && attributeType.equals(type) 1150 && assertionValue != null 1151 && value != null 1152 && orderingMatchingRule != null) 1153 { 1154 try 1155 { 1156 ByteString normValue = orderingMatchingRule.normalizeAttributeValue(value); 1157 Assertion assertion = orderingMatchingRule.getLessOrEqualAssertion(assertionValue); 1158 return assertion.matches(normValue).toBoolean(); 1159 } 1160 catch (DecodeException e) 1161 { 1162 logger.traceException(e); 1163 } 1164 } 1165 return false; 1166 1167 1168 case PRESENT_TYPE: 1169 return attributeType != null && attributeType.equals(type); 1170 1171 1172 case APPROXIMATE_MATCH_TYPE: 1173 if (attributeType != null 1174 && attributeType.equals(type) 1175 && assertionValue != null 1176 && value != null 1177 && approximateMatchingRule != null) 1178 { 1179 return matches(approximateMatchingRule, value, assertionValue); 1180 } 1181 return false; 1182 1183 1184 case EXTENSIBLE_MATCH_TYPE: 1185 if (attributeType == null) 1186 { 1187 return matches(matchingRule, value, assertionValue); 1188 } 1189 else if (!attributeType.equals(type)) 1190 { 1191 return false; 1192 } 1193 return matches(equalityMatchingRule, value, rawAssertionValue); 1194 1195 1196 default: 1197 return false; 1198 } 1199 } 1200 1201 private boolean matches(MatchingRule matchingRule, ByteString value, ByteString assertionValue) 1202 { 1203 if (matchingRule == null || value == null || assertionValue == null) 1204 { 1205 return false; 1206 } 1207 1208 try 1209 { 1210 ByteString normValue = matchingRule.normalizeAttributeValue(value); 1211 Assertion assertion = matchingRule.getAssertion(assertionValue); 1212 return assertion.matches(normValue).toBoolean(); 1213 } 1214 catch (DecodeException e) 1215 { 1216 logger.traceException(e); 1217 return false; 1218 } 1219 } 1220 1221 /** 1222 * Retrieves a string representation of this matched values filter, as an RFC 1223 * 2254-compliant filter string. 1224 * 1225 * @return A string representation of this matched values filter. 1226 */ 1227 @Override 1228 public String toString() 1229 { 1230 StringBuilder buffer = new StringBuilder(); 1231 toString(buffer); 1232 return buffer.toString(); 1233 } 1234 1235 1236 1237 /** 1238 * Appends a string representation of this matched values filter, as an RFC 1239 * 2254-compliant filter string, to the provided buffer. 1240 * 1241 * @param buffer The buffer to which the filter string should be appended. 1242 */ 1243 public void toString(StringBuilder buffer) 1244 { 1245 switch (matchType) 1246 { 1247 case EQUALITY_MATCH_TYPE: 1248 appendAttributeTypeAndAssertion(buffer, "="); 1249 break; 1250 1251 1252 case SUBSTRINGS_TYPE: 1253 buffer.append("("); 1254 buffer.append(rawAttributeType); 1255 buffer.append("="); 1256 if (subInitial != null) 1257 { 1258 RawFilter.valueToFilterString(buffer, subInitial); 1259 } 1260 1261 if (subAny != null) 1262 { 1263 for (ByteString s : subAny) 1264 { 1265 buffer.append("*"); 1266 RawFilter.valueToFilterString(buffer, s); 1267 } 1268 } 1269 1270 buffer.append("*"); 1271 if (subFinal != null) 1272 { 1273 RawFilter.valueToFilterString(buffer, subFinal); 1274 } 1275 buffer.append(")"); 1276 break; 1277 1278 1279 case GREATER_OR_EQUAL_TYPE: 1280 appendAttributeTypeAndAssertion(buffer, ">="); 1281 break; 1282 1283 1284 case LESS_OR_EQUAL_TYPE: 1285 appendAttributeTypeAndAssertion(buffer, "<="); 1286 break; 1287 1288 1289 case PRESENT_TYPE: 1290 buffer.append("("); 1291 buffer.append(rawAttributeType); 1292 buffer.append("=*)"); 1293 break; 1294 1295 1296 case APPROXIMATE_MATCH_TYPE: 1297 appendAttributeTypeAndAssertion(buffer, "~="); 1298 break; 1299 1300 1301 case EXTENSIBLE_MATCH_TYPE: 1302 buffer.append("("); 1303 1304 if (rawAttributeType != null) 1305 { 1306 buffer.append(rawAttributeType); 1307 } 1308 1309 if (matchingRuleID != null) 1310 { 1311 buffer.append(":"); 1312 buffer.append(matchingRuleID); 1313 } 1314 1315 buffer.append(":="); 1316 RawFilter.valueToFilterString(buffer, rawAssertionValue); 1317 buffer.append(")"); 1318 break; 1319 } 1320 } 1321 1322 private void appendAttributeTypeAndAssertion(StringBuilder buffer, String operator) 1323 { 1324 buffer.append("("); 1325 buffer.append(rawAttributeType); 1326 buffer.append(operator); 1327 RawFilter.valueToFilterString(buffer, rawAssertionValue); 1328 buffer.append(")"); 1329 } 1330} 1331