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