001/*
002 * Copyright 2008-2017 UnboundID Corp.
003 * All Rights Reserved.
004 */
005/*
006 * Copyright (C) 2008-2017 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 */
021package com.unboundid.ldap.sdk.controls;
022
023
024
025import java.io.Serializable;
026import java.util.ArrayList;
027import java.util.Arrays;
028
029import com.unboundid.asn1.ASN1Element;
030import com.unboundid.asn1.ASN1OctetString;
031import com.unboundid.asn1.ASN1Sequence;
032import com.unboundid.ldap.sdk.Filter;
033import com.unboundid.ldap.sdk.LDAPException;
034import com.unboundid.ldap.sdk.ResultCode;
035import com.unboundid.util.NotMutable;
036import com.unboundid.util.ThreadSafety;
037import com.unboundid.util.ThreadSafetyLevel;
038
039import static com.unboundid.ldap.sdk.controls.ControlMessages.*;
040import static com.unboundid.util.Debug.*;
041import static com.unboundid.util.StaticUtils.*;
042import 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)
057public 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}