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