001    /*
002     * CDDL HEADER START
003     *
004     * The contents of this file are subject to the terms of the
005     * Common Development and Distribution License, Version 1.0 only
006     * (the "License").  You may not use this file except in compliance
007     * with the License.
008     *
009     * You can obtain a copy of the license at
010     * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011     * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012     * See the License for the specific language governing permissions
013     * and limitations under the License.
014     *
015     * When distributing Covered Code, include this CDDL HEADER in each
016     * file and include the License file at
017     * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
018     * add the following below this CDDL HEADER, with the fields enclosed
019     * by brackets "[]" replaced with your own identifying information:
020     *      Portions Copyright [yyyy] [name of copyright owner]
021     *
022     * CDDL HEADER END
023     *
024     *
025     *      Copyright 2006-2008 Sun Microsystems, Inc.
026     */
027    package org.opends.server.controls;
028    import org.opends.messages.Message;
029    
030    
031    
032    import java.util.ArrayList;
033    import java.util.List;
034    
035    import org.opends.server.api.ApproximateMatchingRule;
036    import org.opends.server.api.EqualityMatchingRule;
037    import org.opends.server.api.MatchingRule;
038    import org.opends.server.api.OrderingMatchingRule;
039    import org.opends.server.api.SubstringMatchingRule;
040    import org.opends.server.core.DirectoryServer;
041    import org.opends.server.protocols.asn1.ASN1Element;
042    import org.opends.server.protocols.asn1.ASN1OctetString;
043    import org.opends.server.protocols.asn1.ASN1Sequence;
044    import org.opends.server.protocols.ldap.LDAPResultCode;
045    import org.opends.server.types.AttributeType;
046    import org.opends.server.types.AttributeValue;
047    import org.opends.server.types.ByteString;
048    import org.opends.server.types.ConditionResult;
049    import org.opends.server.types.LDAPException;
050    import org.opends.server.types.RawFilter;
051    import org.opends.server.util.Validator;
052    
053    import static org.opends.server.loggers.debug.DebugLogger.*;
054    import org.opends.server.loggers.debug.DebugTracer;
055    import org.opends.server.types.DebugLogLevel;
056    import static org.opends.messages.ProtocolMessages.*;
057    import static org.opends.server.protocols.ldap.LDAPConstants.*;
058    import static org.opends.server.util.StaticUtils.*;
059    
060    
061    
062    /**
063     * This class defines a filter that may be used in conjunction with the matched
064     * values control to indicate which particular values of a multivalued attribute
065     * should be returned.  The matched values filter is essentially a subset of an
066     * LDAP search filter, lacking support for AND, OR, and NOT components, and
067     * lacking support for the dnAttributes component of extensible matching
068     * filters.
069     */
070    public class MatchedValuesFilter
071    {
072      /**
073       * The tracer object for the debug logger.
074       */
075      private static final DebugTracer TRACER = getTracer();
076    
077    
078    
079    
080      /**
081       * The BER type associated with the equalityMatch filter type.
082       */
083      public static final byte EQUALITY_MATCH_TYPE = (byte) 0xA3;
084    
085    
086    
087      /**
088       * The BER type associated with the substrings filter type.
089       */
090      public static final byte SUBSTRINGS_TYPE = (byte) 0xA4;
091    
092    
093    
094      /**
095       * The BER type associated with the greaterOrEqual filter type.
096       */
097      public static final byte GREATER_OR_EQUAL_TYPE = (byte) 0xA5;
098    
099    
100    
101      /**
102       * The BER type associated with the lessOrEqual filter type.
103       */
104      public static final byte LESS_OR_EQUAL_TYPE = (byte) 0xA6;
105    
106    
107    
108      /**
109       * The BER type associated with the present filter type.
110       */
111      public static final byte PRESENT_TYPE = (byte) 0x87;
112    
113    
114    
115      /**
116       * The BER type associated with the approxMatch filter type.
117       */
118      public static final byte APPROXIMATE_MATCH_TYPE = (byte) 0xA8;
119    
120    
121    
122      /**
123       * The BER type associated with the extensibleMatch filter type.
124       */
125      public static final byte EXTENSIBLE_MATCH_TYPE = (byte) 0xA9;
126    
127    
128    
129      // The approximate matching rule for this matched values filter.
130      private ApproximateMatchingRule approximateMatchingRule;
131    
132      // The normalized subFinal value for this matched values filter.
133      private ASN1OctetString normalizedSubFinal;
134    
135      // The normalized subInitial value for this matched values filter.
136      private ASN1OctetString normalizedSubInitial;
137    
138      // The raw, unprocessed assertion value for this matched values filter.
139      private ByteString rawAssertionValue;
140    
141      // The subFinal value for this matched values filter.
142      private ByteString subFinal;
143    
144      // The subInitial value for this matched values filter.
145      private ByteString subInitial;
146    
147      // The processed attribute type for this matched values filter.
148      private AttributeType attributeType;
149    
150      // The processed assertion value for this matched values filter.
151      private AttributeValue assertionValue;
152    
153      // Indicates whether the elements of this matched values filter have been
154      // fully decoded.
155      private boolean decoded;
156    
157      // The match type for this matched values filter.
158      private byte matchType;
159    
160      // The equality matching rule for this matched values filter.
161      private EqualityMatchingRule equalityMatchingRule;
162    
163      // The set of normalized subAny values for this matched values filter.
164      private List<ASN1OctetString> normalizedSubAny;
165    
166      // The set of subAny values for this matched values filter.
167      private List<ByteString> subAny;
168    
169      // The matching rule for this matched values filter.
170      private MatchingRule matchingRule;
171    
172      // The ordering matching rule for this matched values filter.
173      private OrderingMatchingRule orderingMatchingRule;
174    
175      // The matching rule ID for this matched values filter.
176      private String matchingRuleID;
177    
178      // The raw, unprocessed attribute type for this matched values filter.
179      private String rawAttributeType;
180    
181      // The substring matching rule for this matched values filter.
182      private SubstringMatchingRule substringMatchingRule;
183    
184    
185    
186      /**
187       * Creates a new matched values filter with the provided information.
188       *
189       * @param  matchType          The match type for this matched values filter.
190       * @param  rawAttributeType   The raw, unprocessed attribute type.
191       * @param  rawAssertionValue  The raw, unprocessed assertion value.
192       * @param  subInitial         The subInitial element.
193       * @param  subAny             The set of subAny elements.
194       * @param  subFinal           The subFinal element.
195       * @param  matchingRuleID     The matching rule ID.
196       */
197      private MatchedValuesFilter(byte matchType, String rawAttributeType,
198                                  ByteString rawAssertionValue,
199                                  ByteString subInitial, List<ByteString> subAny,
200                                  ByteString subFinal, String matchingRuleID)
201      {
202        this.matchType         = matchType;
203        this.rawAttributeType  = rawAttributeType;
204        this.rawAssertionValue = rawAssertionValue;
205        this.subInitial        = subInitial;
206        this.subAny            = subAny;
207        this.subFinal          = subFinal;
208        this.matchingRuleID    = matchingRuleID;
209    
210        decoded                 = false;
211        attributeType           = null;
212        assertionValue          = null;
213        matchingRule            = null;
214        normalizedSubInitial    = null;
215        normalizedSubAny        = null;
216        normalizedSubFinal      = null;
217        approximateMatchingRule = null;
218        equalityMatchingRule    = null;
219        orderingMatchingRule    = null;
220        substringMatchingRule   = null;
221      }
222    
223    
224    
225      /**
226       * Creates a new equalityMatch filter with the provided information.
227       *
228       * @param  rawAttributeType   The raw, unprocessed attribute type.
229       * @param  rawAssertionValue  The raw, unprocessed assertion value.
230       *
231       * @return  The created equalityMatch filter.
232       */
233      public static MatchedValuesFilter createEqualityFilter(
234                                             String rawAttributeType,
235                                             ByteString rawAssertionValue)
236      {
237        Validator.ensureNotNull(rawAttributeType,rawAssertionValue);
238    
239        return new MatchedValuesFilter(EQUALITY_MATCH_TYPE, rawAttributeType,
240                                       rawAssertionValue, null, null, null, null);
241      }
242    
243    
244    
245      /**
246       * Creates a new equalityMatch filter with the provided information.
247       *
248       * @param  attributeType   The attribute type.
249       * @param  assertionValue  The assertion value.
250       *
251       * @return  The created equalityMatch filter.
252       */
253      public static MatchedValuesFilter createEqualityFilter(
254                                             AttributeType attributeType,
255                                             AttributeValue assertionValue)
256      {
257        Validator.ensureNotNull(attributeType, assertionValue);
258        String rawAttributeType = attributeType.getNameOrOID();
259        ASN1OctetString rawAssertionValue = assertionValue.getValue()
260            .toASN1OctetString();
261    
262        MatchedValuesFilter filter =
263             new MatchedValuesFilter(EQUALITY_MATCH_TYPE, rawAttributeType,
264                                     rawAssertionValue, null, null, null, null);
265        filter.attributeType  = attributeType;
266        filter.assertionValue = assertionValue;
267    
268        return filter;
269      }
270    
271    
272    
273      /**
274       * Creates a new substrings filter with the provided information.
275       *
276       * @param  rawAttributeType  The raw, unprocessed attribute type.
277       * @param  subInitial        The subInitial element.
278       * @param  subAny            The set of subAny elements.
279       * @param  subFinal          The subFinal element.
280       *
281       * @return  The created substrings filter.
282       */
283      public static MatchedValuesFilter createSubstringsFilter(
284                                             String rawAttributeType,
285                                             ByteString subInitial,
286                                             List<ByteString> subAny,
287                                             ByteString subFinal)
288      {
289        Validator.ensureNotNull(rawAttributeType);
290        return new MatchedValuesFilter(SUBSTRINGS_TYPE, rawAttributeType, null,
291                                       subInitial, subAny, subFinal, null);
292      }
293    
294    
295    
296      /**
297       * Creates a new substrings filter with the provided information.
298       *
299       * @param  attributeType  The raw, unprocessed attribute type.
300       * @param  subInitial     The subInitial element.
301       * @param  subAny         The set of subAny elements.
302       * @param  subFinal       The subFinal element.
303       *
304       * @return  The created substrings filter.
305       */
306      public static MatchedValuesFilter createSubstringsFilter(
307                                             AttributeType attributeType,
308                                             ByteString subInitial,
309                                             List<ByteString> subAny,
310                                             ByteString subFinal)
311      {
312        Validator.ensureNotNull(attributeType);
313        String rawAttributeType = attributeType.getNameOrOID();
314    
315        MatchedValuesFilter filter =
316             new MatchedValuesFilter(SUBSTRINGS_TYPE, rawAttributeType, null,
317                                     subInitial, subAny, subFinal, null);
318        filter.attributeType  = attributeType;
319    
320        return filter;
321      }
322    
323    
324    
325      /**
326       * Creates a new greaterOrEqual filter with the provided information.
327       *
328       * @param  rawAttributeType   The raw, unprocessed attribute type.
329       * @param  rawAssertionValue  The raw, unprocessed assertion value.
330       *
331       * @return  The created greaterOrEqual filter.
332       */
333      public static MatchedValuesFilter createGreaterOrEqualFilter(
334                                             String rawAttributeType,
335                                             ByteString rawAssertionValue)
336      {
337       Validator.ensureNotNull(rawAttributeType, rawAssertionValue);
338    
339        return new MatchedValuesFilter(GREATER_OR_EQUAL_TYPE, rawAttributeType,
340                                       rawAssertionValue, null, null, null, null);
341      }
342    
343    
344    
345      /**
346       * Creates a new greaterOrEqual filter with the provided information.
347       *
348       * @param  attributeType   The attribute type.
349       * @param  assertionValue  The assertion value.
350       *
351       * @return  The created greaterOrEqual filter.
352       */
353      public static MatchedValuesFilter createGreaterOrEqualFilter(
354                                             AttributeType attributeType,
355                                             AttributeValue assertionValue)
356      {
357        Validator.ensureNotNull(attributeType, assertionValue);
358    
359        String          rawAttributeType  = attributeType.getNameOrOID();
360        ASN1OctetString rawAssertionValue =
361             assertionValue.getValue().toASN1OctetString();
362    
363        MatchedValuesFilter filter =
364             new MatchedValuesFilter(GREATER_OR_EQUAL_TYPE, rawAttributeType,
365                                     rawAssertionValue, null, null, null, null);
366        filter.attributeType  = attributeType;
367        filter.assertionValue = assertionValue;
368    
369        return filter;
370      }
371    
372    
373    
374      /**
375       * Creates a new lessOrEqual filter with the provided information.
376       *
377       * @param  rawAttributeType   The raw, unprocessed attribute type.
378       * @param  rawAssertionValue  The raw, unprocessed assertion value.
379       *
380       * @return  The created lessOrEqual filter.
381       */
382      public static MatchedValuesFilter createLessOrEqualFilter(
383                                             String rawAttributeType,
384                                             ByteString rawAssertionValue)
385      {
386        Validator.ensureNotNull(rawAttributeType, rawAssertionValue);
387        return new MatchedValuesFilter(LESS_OR_EQUAL_TYPE, rawAttributeType,
388                                       rawAssertionValue, null, null, null, null);
389      }
390    
391    
392    
393      /**
394       * Creates a new lessOrEqual filter with the provided information.
395       *
396       * @param  attributeType   The attribute type.
397       * @param  assertionValue  The assertion value.
398       *
399       * @return  The created lessOrEqual filter.
400       */
401      public static MatchedValuesFilter createLessOrEqualFilter(
402                                             AttributeType attributeType,
403                                             AttributeValue assertionValue)
404      {
405        Validator.ensureNotNull(attributeType, assertionValue);
406    
407        String          rawAttributeType = attributeType.getNameOrOID();
408        ASN1OctetString rawAssertionValue =
409             assertionValue.getValue().toASN1OctetString();
410    
411        MatchedValuesFilter filter =
412             new MatchedValuesFilter(LESS_OR_EQUAL_TYPE, rawAttributeType,
413                                     rawAssertionValue, null, null, null, null);
414        filter.attributeType  = attributeType;
415        filter.assertionValue = assertionValue;
416    
417        return filter;
418      }
419    
420    
421    
422      /**
423       * Creates a new present filter with the provided information.
424       *
425       * @param  rawAttributeType  The raw, unprocessed attribute type.
426       *
427       * @return  The created present filter.
428       */
429      public static MatchedValuesFilter createPresentFilter(String rawAttributeType)
430      {
431        Validator.ensureNotNull(rawAttributeType) ;
432        return new MatchedValuesFilter(PRESENT_TYPE, rawAttributeType, null, null,
433                                       null, null, null);
434      }
435    
436    
437    
438      /**
439       * Creates a new present filter with the provided information.
440       *
441       * @param  attributeType  The attribute type.
442       *
443       * @return  The created present filter.
444       */
445      public static MatchedValuesFilter createPresentFilter(
446                                             AttributeType attributeType)
447      {
448        Validator.ensureNotNull(attributeType);
449        String rawAttributeType = attributeType.getNameOrOID();
450    
451        MatchedValuesFilter filter =
452             new MatchedValuesFilter(PRESENT_TYPE, rawAttributeType, null, null,
453                                     null, null, null);
454        filter.attributeType  = attributeType;
455    
456        return filter;
457      }
458    
459    
460    
461      /**
462       * Creates a new approxMatch filter with the provided information.
463       *
464       * @param  rawAttributeType   The raw, unprocessed attribute type.
465       * @param  rawAssertionValue  The raw, unprocessed assertion value.
466       *
467       * @return  The created approxMatch filter.
468       */
469      public static MatchedValuesFilter createApproximateFilter(
470                                             String rawAttributeType,
471                                             ByteString rawAssertionValue)
472      {
473        Validator.ensureNotNull(rawAttributeType,rawAssertionValue);
474    
475        return new MatchedValuesFilter(APPROXIMATE_MATCH_TYPE, rawAttributeType,
476                                       rawAssertionValue, null, null, null, null);
477      }
478    
479    
480    
481      /**
482       * Creates a new approxMatch filter with the provided information.
483       *
484       * @param  attributeType   The attribute type.
485       * @param  assertionValue  The assertion value.
486       *
487       * @return  The created approxMatch filter.
488       */
489      public static MatchedValuesFilter createApproximateFilter(
490                                             AttributeType attributeType,
491                                             AttributeValue assertionValue)
492      {
493        Validator.ensureNotNull(attributeType,assertionValue);
494        String          rawAttributeType  = attributeType.getNameOrOID();
495        ASN1OctetString rawAssertionValue =
496             assertionValue.getValue().toASN1OctetString();
497    
498        MatchedValuesFilter filter =
499             new MatchedValuesFilter(APPROXIMATE_MATCH_TYPE, rawAttributeType,
500                                     rawAssertionValue, null, null, null, null);
501        filter.attributeType  = attributeType;
502        filter.assertionValue = assertionValue;
503    
504        return filter;
505      }
506    
507    
508    
509      /**
510       * Creates a new extensibleMatch filter with the provided information.
511       *
512       * @param  rawAttributeType   The raw, unprocessed attribute type.
513       * @param  matchingRuleID     The matching rule ID.
514       * @param  rawAssertionValue  The raw, unprocessed assertion value.
515       *
516       * @return  The created extensibleMatch filter.
517       */
518      public static MatchedValuesFilter createExtensibleMatchFilter(
519                                             String rawAttributeType,
520                                             String matchingRuleID,
521                                             ByteString rawAssertionValue)
522      {
523        Validator
524            .ensureNotNull(rawAttributeType, matchingRuleID, rawAssertionValue);
525        return new MatchedValuesFilter(EXTENSIBLE_MATCH_TYPE, rawAttributeType,
526                                       rawAssertionValue, null, null, null,
527                                       matchingRuleID);
528      }
529    
530    
531    
532      /**
533       * Creates a new extensibleMatch filter with the provided information.
534       *
535       * @param  attributeType   The attribute type.
536       * @param  matchingRule    The matching rule.
537       * @param  assertionValue  The assertion value.
538       *
539       * @return  The created extensibleMatch filter.
540       */
541      public static MatchedValuesFilter createExtensibleMatchFilter(
542                                             AttributeType attributeType,
543                                             MatchingRule matchingRule,
544                                             AttributeValue assertionValue)
545      {
546        Validator.ensureNotNull(attributeType, matchingRule, assertionValue);
547        String rawAttributeType = attributeType.getNameOrOID();
548        String matchingRuleID = matchingRule.getOID();
549        ASN1OctetString rawAssertionValue =
550             assertionValue.getValue().toASN1OctetString();
551    
552        MatchedValuesFilter filter =
553             new MatchedValuesFilter(EXTENSIBLE_MATCH_TYPE, rawAttributeType,
554                                     rawAssertionValue, null, null, null,
555                                     matchingRuleID);
556        filter.attributeType  = attributeType;
557        filter.assertionValue = assertionValue;
558        filter.matchingRule   = matchingRule;
559    
560        return filter;
561      }
562    
563    
564    
565      /**
566       * Creates a new matched values filter from the provided LDAP filter.
567       *
568       * @param  filter  The LDAP filter to use for this matched values filter.
569       *
570       * @return  The corresponding matched values filter.
571       *
572       * @throws  LDAPException  If the provided LDAP filter cannot be treated as a
573       *                         matched values filter.
574       */
575      public static MatchedValuesFilter createFromLDAPFilter(RawFilter filter)
576             throws LDAPException
577      {
578        switch (filter.getFilterType())
579        {
580          case AND:
581          case OR:
582          case NOT:
583            // These filter types cannot be used in a matched values filter.
584            Message message = ERR_MVFILTER_INVALID_LDAP_FILTER_TYPE.get(
585                String.valueOf(filter), String.valueOf(filter.getFilterType()));
586            throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
587    
588    
589          case EQUALITY:
590            return new MatchedValuesFilter(EQUALITY_MATCH_TYPE,
591                                           filter.getAttributeType(),
592                                           filter.getAssertionValue(), null, null,
593                                           null, null);
594    
595    
596          case SUBSTRING:
597            return new MatchedValuesFilter(SUBSTRINGS_TYPE,
598                                           filter.getAttributeType(), null,
599                                           filter.getSubInitialElement(),
600                                           filter.getSubAnyElements(),
601                                           filter.getSubFinalElement(), null);
602    
603    
604          case GREATER_OR_EQUAL:
605            return new MatchedValuesFilter(GREATER_OR_EQUAL_TYPE,
606                                           filter.getAttributeType(),
607                                           filter.getAssertionValue(), null, null,
608                                           null, null);
609    
610    
611          case LESS_OR_EQUAL:
612            return new MatchedValuesFilter(LESS_OR_EQUAL_TYPE,
613                                           filter.getAttributeType(),
614                                           filter.getAssertionValue(), null, null,
615                                           null, null);
616    
617    
618          case PRESENT:
619            return new MatchedValuesFilter(PRESENT_TYPE, filter.getAttributeType(),
620                                           null, null, null, null, null);
621    
622    
623          case APPROXIMATE_MATCH:
624            return new MatchedValuesFilter(APPROXIMATE_MATCH_TYPE,
625                                           filter.getAttributeType(),
626                                           filter.getAssertionValue(), null, null,
627                                           null, null);
628    
629    
630          case EXTENSIBLE_MATCH:
631            if (filter.getDNAttributes())
632            {
633              // This cannot be represented in a matched values filter.
634              message = ERR_MVFILTER_INVALID_DN_ATTRIBUTES_FLAG.get(
635                  String.valueOf(filter));
636              throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
637            }
638            else
639            {
640              return new MatchedValuesFilter(EXTENSIBLE_MATCH_TYPE,
641                                             filter.getAttributeType(),
642                                             filter.getAssertionValue(), null, null,
643                                             null, filter.getMatchingRuleID());
644            }
645    
646    
647          default:
648            message = ERR_MVFILTER_INVALID_LDAP_FILTER_TYPE.get(
649                String.valueOf(filter), String.valueOf(filter.getFilterType()));
650            throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
651        }
652      }
653    
654    
655    
656      /**
657       * Encodes this matched values filter as an ASN.1 element.
658       *
659       * @return  The ASN.1 element containing the encoded matched values filter.
660       */
661      public ASN1Element encode()
662      {
663        switch (matchType)
664        {
665          case EQUALITY_MATCH_TYPE:
666          case GREATER_OR_EQUAL_TYPE:
667          case LESS_OR_EQUAL_TYPE:
668          case APPROXIMATE_MATCH_TYPE:
669            // These will all be encoded in the same way.
670            ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2);
671            elements.add(new ASN1OctetString(rawAttributeType));
672            elements.add(rawAssertionValue.toASN1OctetString());
673            return new ASN1Sequence(matchType, elements);
674    
675    
676          case SUBSTRINGS_TYPE:
677            ArrayList<ASN1Element> subElements = new ArrayList<ASN1Element>();
678            if (subInitial != null)
679            {
680              ASN1OctetString subInitialOS = subInitial.toASN1OctetString();
681              subInitialOS.setType(TYPE_SUBINITIAL);
682              subElements.add(subInitialOS);
683            }
684    
685            if (subAny != null)
686            {
687              for (ByteString s : subAny)
688              {
689                ASN1OctetString os = s.toASN1OctetString();
690                os.setType(TYPE_SUBANY);
691                subElements.add(os);
692              }
693            }
694    
695            if (subFinal != null)
696            {
697              ASN1OctetString subFinalOS = subFinal.toASN1OctetString();
698              subFinalOS.setType(TYPE_SUBFINAL);
699              subElements.add(subFinalOS);
700            }
701    
702            elements = new ArrayList<ASN1Element>(2);
703            elements.add(new ASN1OctetString(rawAttributeType));
704            elements.add(new ASN1Sequence(subElements));
705            return new ASN1Sequence(matchType, elements);
706    
707    
708          case PRESENT_TYPE:
709            return new ASN1OctetString(matchType, rawAttributeType);
710    
711    
712          case EXTENSIBLE_MATCH_TYPE:
713            elements = new ArrayList<ASN1Element>(3);
714            if (matchingRuleID != null)
715            {
716              elements.add(new ASN1OctetString(TYPE_MATCHING_RULE_ID,
717                                               matchingRuleID));
718            }
719    
720            if (rawAttributeType != null)
721            {
722              elements.add(new ASN1OctetString(TYPE_MATCHING_RULE_TYPE,
723                                               rawAttributeType));
724            }
725    
726            ASN1OctetString valueOS = rawAssertionValue.toASN1OctetString();
727            valueOS.setType(TYPE_MATCHING_RULE_VALUE);
728            elements.add(valueOS);
729            return new ASN1Sequence(matchType, elements);
730    
731    
732          default:
733            return null;
734        }
735      }
736    
737    
738    
739      /**
740       * Decodes the provided ASN.1 element as a matched values filter item.
741       *
742       * @param  element  The ASN.1 element to be decoded.
743       *
744       * @return  The decoded matched values filter.
745       *
746       * @throws  LDAPException  If a problem occurs while attempting to decode the
747       *                         filter item.
748       */
749      public static MatchedValuesFilter decode(ASN1Element element)
750             throws LDAPException
751      {
752        switch (element.getType())
753        {
754          case EQUALITY_MATCH_TYPE:
755          case GREATER_OR_EQUAL_TYPE:
756          case LESS_OR_EQUAL_TYPE:
757          case APPROXIMATE_MATCH_TYPE:
758            // These will all be decoded in the same manner.  The element must be a
759            // sequence consisting of the attribute type and assertion value.
760            try
761            {
762              ArrayList<ASN1Element> elements =
763                   element.decodeAsSequence().elements();
764              if (elements.size() != 2)
765              {
766                Message message =
767                    ERR_MVFILTER_INVALID_AVA_SEQUENCE_SIZE.get(elements.size());
768                throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
769              }
770    
771              String rawAttributeType =
772                          elements.get(0).decodeAsOctetString().stringValue();
773    
774              return new MatchedValuesFilter(element.getType(), rawAttributeType,
775                                             elements.get(1).decodeAsOctetString(),
776                                             null, null, null, null);
777            }
778            catch (LDAPException le)
779            {
780              throw le;
781            }
782            catch (Exception e)
783            {
784              if (debugEnabled())
785              {
786                TRACER.debugCaught(DebugLogLevel.ERROR, e);
787              }
788    
789              Message message =
790                  ERR_MVFILTER_CANNOT_DECODE_AVA.get(getExceptionMessage(e));
791              throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message,
792                                      e);
793            }
794    
795    
796          case SUBSTRINGS_TYPE:
797            // This must be a sequence of two elements, where the second is a
798            // sequence of substring types.
799            try
800            {
801              ArrayList<ASN1Element> elements =
802                   element.decodeAsSequence().elements();
803              if (elements.size() != 2)
804              {
805                Message message = ERR_MVFILTER_INVALID_SUBSTRING_SEQUENCE_SIZE.get(
806                    elements.size());
807                throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
808              }
809    
810              ArrayList<ASN1Element> subElements =
811                   elements.get(1).decodeAsSequence().elements();
812              if (subElements.isEmpty())
813              {
814                Message message = ERR_MVFILTER_NO_SUBSTRING_ELEMENTS.get();
815                throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
816              }
817    
818              String rawAttributeType =
819                          elements.get(0).decodeAsOctetString().stringValue();
820    
821              ByteString subInitial        = null;
822              ArrayList<ByteString> subAny = null;
823              ByteString subFinal          = null;
824              for (ASN1Element e : subElements)
825              {
826                switch (e.getType())
827                {
828                  case TYPE_SUBINITIAL:
829                    if (subInitial == null)
830                    {
831                      subInitial = e.decodeAsOctetString();
832                    }
833                    else
834                    {
835                      Message message = ERR_MVFILTER_MULTIPLE_SUBINITIALS.get();
836                      throw new LDAPException(
837                              LDAPResultCode.PROTOCOL_ERROR, message);
838                    }
839                    break;
840    
841                  case TYPE_SUBANY:
842                    if (subAny == null)
843                    {
844                      subAny = new ArrayList<ByteString>();
845                    }
846    
847                    subAny.add(e.decodeAsOctetString());
848                    break;
849    
850                  case TYPE_SUBFINAL:
851                    if (subFinal == null)
852                    {
853                      subFinal = e.decodeAsOctetString();
854                    }
855                    else
856                    {
857                      Message message = ERR_MVFILTER_MULTIPLE_SUBFINALS.get();
858                      throw new LDAPException(
859                              LDAPResultCode.PROTOCOL_ERROR, message);
860                    }
861                    break;
862    
863                  default:
864                    Message message = ERR_MVFILTER_INVALID_SUBSTRING_ELEMENT_TYPE.
865                        get(byteToHex(e.getType()));
866                    throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
867                }
868              }
869    
870              return new MatchedValuesFilter(element.getType(), rawAttributeType,
871                                             null, subInitial, subAny, subFinal,
872                                             null);
873            }
874            catch (LDAPException le)
875            {
876              throw le;
877            }
878            catch (Exception e)
879            {
880              if (debugEnabled())
881              {
882                TRACER.debugCaught(DebugLogLevel.ERROR, e);
883              }
884    
885              Message message =
886                  ERR_MVFILTER_CANNOT_DECODE_SUBSTRINGS.get(getExceptionMessage(e));
887              throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message,
888                                      e);
889            }
890    
891    
892          case PRESENT_TYPE:
893            // The element must be an ASN.1 octet string holding the attribute type.
894            try
895            {
896              String rawAttributeType = element.decodeAsOctetString().stringValue();
897    
898              return new MatchedValuesFilter(element.getType(), rawAttributeType,
899                                             null, null, null, null, null);
900            }
901            catch (Exception e)
902            {
903              if (debugEnabled())
904              {
905                TRACER.debugCaught(DebugLogLevel.ERROR, e);
906              }
907    
908              Message message = ERR_MVFILTER_CANNOT_DECODE_PRESENT_TYPE.get(
909                  getExceptionMessage(e));
910              throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message,
911                                      e);
912            }
913    
914    
915          case EXTENSIBLE_MATCH_TYPE:
916            // This must be a two or three element sequence with an assertion value
917            // as the last element and an attribute type and/or matching rule ID as
918            // the first element(s).
919            try
920            {
921              ArrayList<ASN1Element> elements =
922                   element.decodeAsSequence().elements();
923              if ((elements.size() < 2) || (elements.size() > 3))
924              {
925                Message message = ERR_MVFILTER_INVALID_EXTENSIBLE_SEQUENCE_SIZE.get(
926                    elements.size());
927                throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
928              }
929    
930    
931              String          rawAttributeType  = null;
932              String          matchingRuleID    = null;
933              ASN1OctetString rawAssertionValue = null;
934              for (ASN1Element e : elements)
935              {
936                switch (e.getType())
937                {
938                  case TYPE_MATCHING_RULE_ID:
939                    if (matchingRuleID == null)
940                    {
941                      matchingRuleID = e.decodeAsOctetString().stringValue();
942                    }
943                    else
944                    {
945                      Message message =
946                          ERR_MVFILTER_MULTIPLE_MATCHING_RULE_IDS.get();
947                      throw new LDAPException(
948                              LDAPResultCode.PROTOCOL_ERROR, message);
949                    }
950                    break;
951    
952                  case TYPE_MATCHING_RULE_TYPE:
953                    if (rawAttributeType == null)
954                    {
955                      rawAttributeType = e.decodeAsOctetString().stringValue();
956                    }
957                    else
958                    {
959                      Message message = ERR_MVFILTER_MULTIPLE_ATTRIBUTE_TYPES.get();
960                      throw new LDAPException(
961                              LDAPResultCode.PROTOCOL_ERROR, message);
962                    }
963                    break;
964    
965                  case TYPE_MATCHING_RULE_VALUE:
966                    if (rawAssertionValue == null)
967                    {
968                      rawAssertionValue = e.decodeAsOctetString();
969                    }
970                    else
971                    {
972                      Message message =
973                          ERR_MVFILTER_MULTIPLE_ASSERTION_VALUES.get();
974                      throw new LDAPException(
975                              LDAPResultCode.PROTOCOL_ERROR, message);
976                    }
977                    break;
978    
979                  default:
980                    Message message = ERR_MVFILTER_INVALID_EXTENSIBLE_ELEMENT_TYPE.
981                        get(byteToHex(e.getType()));
982                    throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
983                }
984              }
985    
986    
987              return new MatchedValuesFilter(element.getType(), rawAttributeType,
988                                             rawAssertionValue, null, null, null,
989                                             matchingRuleID);
990            }
991            catch (LDAPException le)
992            {
993              throw le;
994            }
995            catch (Exception e)
996            {
997              if (debugEnabled())
998              {
999                TRACER.debugCaught(DebugLogLevel.ERROR, e);
1000              }
1001    
1002              Message message = ERR_MVFILTER_CANNOT_DECODE_EXTENSIBLE_MATCH.get(
1003                  getExceptionMessage(e));
1004              throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message,
1005                                      e);
1006            }
1007    
1008    
1009          default:
1010            Message message =
1011                ERR_MVFILTER_INVALID_ELEMENT_TYPE.get(byteToHex(element.getType()));
1012            throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
1013        }
1014      }
1015    
1016    
1017    
1018      /**
1019       * Retrieves the match type for this matched values filter.
1020       *
1021       * @return  The match type for this matched values filter.
1022       */
1023      public byte getMatchType()
1024      {
1025        return matchType;
1026      }
1027    
1028    
1029    
1030      /**
1031       * Retrieves the raw, unprocessed attribute type for this matched values
1032       * filter.
1033       *
1034       * @return  The raw, unprocessed attribute type for this matched values
1035       *          filter, or <CODE>null</CODE> if there is none.
1036       */
1037      public String getRawAttributeType()
1038      {
1039        return rawAttributeType;
1040      }
1041    
1042    
1043    
1044      /**
1045       * Specifies the raw, unprocessed attribute type for this matched values
1046       * filter.
1047       *
1048       * @param  rawAttributeType  The raw, unprocessed attribute type for this
1049       *                           matched values filter.
1050       */
1051      public void setRawAttributeType(String rawAttributeType)
1052      {
1053        this.rawAttributeType = rawAttributeType;
1054    
1055        decoded                 = false;
1056        attributeType           = null;
1057        approximateMatchingRule = null;
1058        equalityMatchingRule    = null;
1059        orderingMatchingRule    = null;
1060        substringMatchingRule   = null;
1061      }
1062    
1063    
1064    
1065      /**
1066       * Retrieves the attribute type for this matched values filter.
1067       *
1068       * @return  The attribute type for this matched values filter, or
1069       *          <CODE>null</CODE> if there is none.
1070       */
1071      public AttributeType getAttributeType()
1072      {
1073        if (attributeType == null)
1074        {
1075          if (rawAttributeType != null)
1076          {
1077            attributeType =
1078                 DirectoryServer.getAttributeType(toLowerCase(rawAttributeType));
1079            if (attributeType == null)
1080            {
1081              attributeType =
1082                   DirectoryServer.getDefaultAttributeType(rawAttributeType);
1083            }
1084          }
1085        }
1086    
1087        return attributeType;
1088      }
1089    
1090    
1091    
1092      /**
1093       * Specifies the attribute type for this matched values filter.
1094       *
1095       * @param  attributeType  The attribute type for this matched values filter.
1096       */
1097      public void setAttributeType(AttributeType attributeType)
1098      {
1099        this.attributeType = attributeType;
1100    
1101        if (attributeType == null)
1102        {
1103          rawAttributeType = null;
1104        }
1105        else
1106        {
1107          rawAttributeType = attributeType.getNameOrOID();
1108        }
1109    
1110        decoded                 = false;
1111        approximateMatchingRule = null;
1112        equalityMatchingRule    = null;
1113        orderingMatchingRule    = null;
1114        substringMatchingRule   = null;
1115      }
1116    
1117    
1118    
1119      /**
1120       * Retrieves the raw, unprocessed assertion value for this matched values
1121       * filter.
1122       *
1123       * @return  The raw, unprocessed assertion value for this matched values
1124       *          filter, or <CODE>null</CODE> if there is none.
1125       */
1126      public ByteString getRawAssertionValue()
1127      {
1128        return rawAssertionValue;
1129      }
1130    
1131    
1132    
1133      /**
1134       * Specifies the raw, unprocessed assertion value for this matched values
1135       * filter.
1136       *
1137       * @param  rawAssertionValue  The raw, unprocessed assertion value for this
1138       *                            matched values filter.
1139       */
1140      public void setRawAssertionValue(ByteString rawAssertionValue)
1141      {
1142        this.rawAssertionValue = rawAssertionValue;
1143    
1144        decoded        = false;
1145        assertionValue = null;
1146      }
1147    
1148    
1149    
1150      /**
1151       * Retrieves the assertion value for this matched values filter.
1152       *
1153       * @return  The assertion value for this matched values filter, or
1154       *          <CODE>null</CODE> if there is none.
1155       */
1156      public AttributeValue getAssertionValue()
1157      {
1158        if (assertionValue == null)
1159        {
1160          if (rawAssertionValue != null)
1161          {
1162            assertionValue = new AttributeValue(getAttributeType(),
1163                                                rawAssertionValue);
1164          }
1165        }
1166    
1167        return assertionValue;
1168      }
1169    
1170    
1171    
1172      /**
1173       * Specifies the assertion value for this matched values filter.
1174       *
1175       * @param  assertionValue  The assertion value for this matched values filter.
1176       */
1177      public void setAssertionValue(AttributeValue assertionValue)
1178      {
1179        this.assertionValue = assertionValue;
1180    
1181        if (assertionValue == null)
1182        {
1183          rawAssertionValue = null;
1184        }
1185        else
1186        {
1187          rawAssertionValue = assertionValue.getValue().toASN1OctetString();
1188        }
1189    
1190        decoded = false;
1191      }
1192    
1193    
1194    
1195      /**
1196       * Retrieves the subInitial element for this matched values filter.
1197       *
1198       * @return  The subInitial element for this matched values filter, or
1199       *          <CODE>null</CODE> if there is none.
1200       */
1201      public ByteString getSubInitialElement()
1202      {
1203        return subInitial;
1204      }
1205    
1206    
1207    
1208      /**
1209       * Specifies the subInitial element for this matched values filter.
1210       *
1211       * @param  subInitial  The subInitial element for this matched values filter.
1212       */
1213      public void setSubInitialElement(ByteString subInitial)
1214      {
1215        this.subInitial = subInitial;
1216    
1217        decoded              = false;
1218        normalizedSubInitial = null;
1219      }
1220    
1221    
1222    
1223      /**
1224       * Retrieves the normalized form of the subInitial element.
1225       *
1226       * @return  The normalized form of the subInitial element, or
1227       *          <CODE>null</CODE> if there is none.
1228       */
1229      public ASN1OctetString getNormalizedSubInitialElement()
1230      {
1231        if (normalizedSubInitial == null)
1232        {
1233          if ((subInitial != null) && (getSubstringMatchingRule() != null))
1234          {
1235            try
1236            {
1237              normalizedSubInitial =
1238                   getSubstringMatchingRule().normalizeSubstring(subInitial).
1239                        toASN1OctetString();
1240            }
1241            catch (Exception e)
1242            {
1243              if (debugEnabled())
1244              {
1245                TRACER.debugCaught(DebugLogLevel.ERROR, e);
1246              }
1247            }
1248          }
1249        }
1250    
1251        return normalizedSubInitial;
1252      }
1253    
1254    
1255    
1256      /**
1257       * Retrieves the set of subAny elements for this matched values filter.
1258       *
1259       * @return  The set of subAny elements for this matched values filter.  If
1260       *          there are none, then the return value may be either
1261       *          <CODE>null</CODE> or an empty list.
1262       */
1263      public List<ByteString> getSubAnyElements()
1264      {
1265        return subAny;
1266      }
1267    
1268    
1269    
1270      /**
1271       * Specifies the set of subAny elements for this matched values filter.
1272       *
1273       * @param  subAny  The set of subAny elements for this matched values filter.
1274       */
1275      public void setSubAnyElements(List<ByteString> subAny)
1276      {
1277        this.subAny = subAny;
1278    
1279        decoded          = false;
1280        normalizedSubAny = null;
1281      }
1282    
1283    
1284    
1285      /**
1286       * Retrieves the set of normalized subAny elements for this matched values
1287       * filter.
1288       *
1289       * @return  The set of subAny elements for this matched values filter.  If
1290       *          there are none, then an empty list will be returned.  If a
1291       *          problem occurs while attempting to perform the normalization, then
1292       *          <CODE>null</CODE> will be returned.
1293       */
1294      public List<ASN1OctetString> getNormalizedSubAnyElements()
1295      {
1296        if (normalizedSubAny == null)
1297        {
1298          if ((subAny == null) || (subAny.isEmpty()))
1299          {
1300            normalizedSubAny = new ArrayList<ASN1OctetString>(0);
1301          }
1302          else
1303          {
1304            if (getSubstringMatchingRule() == null)
1305            {
1306              return null;
1307            }
1308    
1309            normalizedSubAny = new ArrayList<ASN1OctetString>();
1310            try
1311            {
1312              for (ByteString s : subAny)
1313              {
1314                normalizedSubAny.add(
1315                     substringMatchingRule.normalizeSubstring(s).
1316                          toASN1OctetString());
1317              }
1318            }
1319            catch (Exception e)
1320            {
1321              if (debugEnabled())
1322              {
1323                TRACER.debugCaught(DebugLogLevel.ERROR, e);
1324              }
1325    
1326              normalizedSubAny = null;
1327            }
1328          }
1329        }
1330    
1331        return normalizedSubAny;
1332      }
1333    
1334    
1335    
1336      /**
1337       * Retrieves the subFinal element for this matched values filter.
1338       *
1339       * @return  The subFinal element for this matched values filter, or
1340       *          <CODE>null</CODE> if there is none.
1341       */
1342      public ByteString getSubFinalElement()
1343      {
1344        return subFinal;
1345      }
1346    
1347    
1348    
1349      /**
1350       * Specifies the subFinal element for this matched values filter.
1351       *
1352       * @param  subFinal  The subFinal element for this matched values filter.
1353       */
1354      public void setSubFinalElement(ByteString subFinal)
1355      {
1356        this.subFinal = subFinal;
1357    
1358        decoded            = false;
1359        normalizedSubFinal = null;
1360      }
1361    
1362    
1363    
1364      /**
1365       * Retrieves the normalized form of the subFinal element.
1366       *
1367       * @return  The normalized form of the subFinal element, or <CODE>null</CODE>
1368       *          if there is none.
1369       */
1370      public ASN1OctetString getNormalizedSubFinalElement()
1371      {
1372        if (normalizedSubFinal == null)
1373        {
1374          if ((subFinal != null) && (getSubstringMatchingRule() != null))
1375          {
1376            try
1377            {
1378              normalizedSubFinal =
1379                   getSubstringMatchingRule().normalizeSubstring(subFinal).
1380                        toASN1OctetString();
1381            }
1382            catch (Exception e)
1383            {
1384              if (debugEnabled())
1385              {
1386                TRACER.debugCaught(DebugLogLevel.ERROR, e);
1387              }
1388            }
1389          }
1390        }
1391    
1392        return normalizedSubFinal;
1393      }
1394    
1395    
1396    
1397      /**
1398       * Retrieves the matching rule ID for this matched values filter.
1399       *
1400       * @return  The matching rule ID for this matched values filter, or
1401       *          <CODE>null</CODE> if there is none.
1402       */
1403      public String getMatchingRuleID()
1404      {
1405        return matchingRuleID;
1406      }
1407    
1408    
1409    
1410      /**
1411       * Specifies the matching rule ID for this matched values filter.
1412       *
1413       * @param  matchingRuleID  The matching rule ID for this matched values
1414       *                         filter.
1415       */
1416      public void setMatchingRuleID(String matchingRuleID)
1417      {
1418        this.matchingRuleID = matchingRuleID;
1419    
1420        decoded      = false;
1421        matchingRule = null;
1422      }
1423    
1424    
1425    
1426      /**
1427       * Retrieves the matching rule for this matched values filter.
1428       *
1429       * @return  The matching rule for this matched values filter, or
1430       *          <CODE>null</CODE> if there is none.
1431       */
1432      public MatchingRule getMatchingRule()
1433      {
1434        if (matchingRule == null)
1435        {
1436          if (matchingRuleID != null)
1437          {
1438            matchingRule =
1439                 DirectoryServer.getMatchingRule(toLowerCase(matchingRuleID));
1440          }
1441        }
1442    
1443        return matchingRule;
1444      }
1445    
1446    
1447    
1448      /**
1449       * Specifies the matching rule for this matched values filter.
1450       *
1451       * @param  matchingRule  The matching rule for this matched values filter.
1452       */
1453      public void setMatchingRule(MatchingRule matchingRule)
1454      {
1455        this.matchingRule = matchingRule;
1456    
1457        if (matchingRule == null)
1458        {
1459          matchingRuleID = null;
1460        }
1461        else
1462        {
1463          matchingRuleID = matchingRule.getNameOrOID();
1464        }
1465    
1466        decoded = false;
1467      }
1468    
1469    
1470    
1471      /**
1472       * Retrieves the approximate matching rule that should be used for this
1473       * matched values filter.
1474       *
1475       * @return  The approximate matching rule that should be used for this matched
1476       *          values filter, or <CODE>null</CODE> if there is none.
1477       */
1478      public ApproximateMatchingRule getApproximateMatchingRule()
1479      {
1480        if (approximateMatchingRule == null)
1481        {
1482          AttributeType attrType = getAttributeType();
1483          if (attrType != null)
1484          {
1485            approximateMatchingRule = attrType.getApproximateMatchingRule();
1486          }
1487        }
1488    
1489        return approximateMatchingRule;
1490      }
1491    
1492    
1493    
1494      /**
1495       * Retrieves the equality matching rule that should be used for this matched
1496       * values filter.
1497       *
1498       * @return  The equality matching rule that should be used for this matched
1499       *          values filter, or <CODE>null</CODE> if there is none.
1500       */
1501      public EqualityMatchingRule getEqualityMatchingRule()
1502      {
1503        if (equalityMatchingRule == null)
1504        {
1505          AttributeType attrType = getAttributeType();
1506          if (attrType != null)
1507          {
1508            equalityMatchingRule = attrType.getEqualityMatchingRule();
1509          }
1510        }
1511    
1512        return equalityMatchingRule;
1513      }
1514    
1515    
1516    
1517      /**
1518       * Retrieves the ordering matching rule that should be used for this matched
1519       * values filter.
1520       *
1521       * @return  The ordering matching rule that should be used for this matched
1522       *          values filter, or <CODE>null</CODE> if there is none.
1523       */
1524      public OrderingMatchingRule getOrderingMatchingRule()
1525      {
1526        if (orderingMatchingRule == null)
1527        {
1528          AttributeType attrType = getAttributeType();
1529          if (attrType != null)
1530          {
1531            orderingMatchingRule = attrType.getOrderingMatchingRule();
1532          }
1533        }
1534    
1535        return orderingMatchingRule;
1536      }
1537    
1538    
1539    
1540      /**
1541       * Retrieves the substring matching rule that should be used for this matched
1542       * values filter.
1543       *
1544       * @return  The substring matching rule that should be used for this matched
1545       *          values filter, or <CODE>null</CODE> if there is none.
1546       */
1547      public SubstringMatchingRule getSubstringMatchingRule()
1548      {
1549        if (substringMatchingRule == null)
1550        {
1551          AttributeType attrType = getAttributeType();
1552          if (attrType != null)
1553          {
1554            substringMatchingRule = attrType.getSubstringMatchingRule();
1555          }
1556        }
1557    
1558        return substringMatchingRule;
1559      }
1560    
1561    
1562    
1563      /**
1564       * Decodes all components of the matched values filter so that they can be
1565       * referenced as member variables.
1566       */
1567      private void fullyDecode()
1568      {
1569        if (! decoded)
1570        {
1571          getAttributeType();
1572          getAssertionValue();
1573          getNormalizedSubInitialElement();
1574          getNormalizedSubAnyElements();
1575          getNormalizedSubFinalElement();
1576          getMatchingRule();
1577          getApproximateMatchingRule();
1578          getEqualityMatchingRule();
1579          getOrderingMatchingRule();
1580          getSubstringMatchingRule();
1581          decoded = true;
1582        }
1583      }
1584    
1585    
1586    
1587      /**
1588       * Indicates whether the specified attribute value matches the criteria
1589       * defined in this matched values filter.
1590       *
1591       * @param  type   The attribute type with which the provided value is
1592       *                associated.
1593       * @param  value  The attribute value for which to make the determination.
1594       *
1595       * @return  <CODE>true</CODE> if the specified attribute value matches the
1596       *          criteria defined in this matched values filter, or
1597       *          <CODE>false</CODE> if not.
1598       */
1599      public boolean valueMatches(AttributeType type, AttributeValue value)
1600      {
1601        fullyDecode();
1602    
1603        switch (matchType)
1604        {
1605          case EQUALITY_MATCH_TYPE:
1606            if ((attributeType != null) && (type != null) &&
1607                attributeType.equals(type) && (assertionValue != null) &&
1608                (value != null) && (equalityMatchingRule != null))
1609            {
1610              try
1611              {
1612                return equalityMatchingRule.areEqual(
1613                            assertionValue.getNormalizedValue(),
1614                            value.getNormalizedValue());
1615              }
1616              catch (Exception e)
1617              {
1618                if (debugEnabled())
1619                {
1620                  TRACER.debugCaught(DebugLogLevel.ERROR, e);
1621                }
1622    
1623                return false;
1624              }
1625            }
1626            else
1627            {
1628              return false;
1629            }
1630    
1631    
1632          case SUBSTRINGS_TYPE:
1633            if ((attributeType != null) && (type != null) &&
1634                attributeType.equals(type) && (substringMatchingRule != null))
1635            {
1636              try
1637              {
1638                ArrayList<ByteString> normalizedSubAnyBS =
1639                     new ArrayList<ByteString>(normalizedSubAny);
1640    
1641                return substringMatchingRule.valueMatchesSubstring(
1642                     value.getNormalizedValue(), normalizedSubInitial,
1643                     normalizedSubAnyBS, normalizedSubFinal);
1644              }
1645              catch (Exception e)
1646              {
1647                if (debugEnabled())
1648                {
1649                  TRACER.debugCaught(DebugLogLevel.ERROR, e);
1650                }
1651    
1652                return false;
1653              }
1654            }
1655            else
1656            {
1657              return false;
1658            }
1659    
1660    
1661          case GREATER_OR_EQUAL_TYPE:
1662            if ((attributeType != null) && (type != null) &&
1663                attributeType.equals(type) && (assertionValue != null) &&
1664                (value != null) && (orderingMatchingRule != null))
1665            {
1666              try
1667              {
1668                return (orderingMatchingRule.compareValues(
1669                             assertionValue.getNormalizedValue(),
1670                             value.getNormalizedValue()) >= 0);
1671              }
1672              catch (Exception e)
1673              {
1674                if (debugEnabled())
1675                {
1676                  TRACER.debugCaught(DebugLogLevel.ERROR, e);
1677                }
1678    
1679                return false;
1680              }
1681            }
1682            else
1683            {
1684              return false;
1685            }
1686    
1687    
1688          case LESS_OR_EQUAL_TYPE:
1689            if ((attributeType != null) && (type != null) &&
1690                attributeType.equals(type) && (assertionValue != null) &&
1691                (value != null) && (orderingMatchingRule != null))
1692            {
1693              try
1694              {
1695                return (orderingMatchingRule.compareValues(
1696                             assertionValue.getNormalizedValue(),
1697                             value.getNormalizedValue()) <= 0);
1698              }
1699              catch (Exception e)
1700              {
1701                if (debugEnabled())
1702                {
1703                  TRACER.debugCaught(DebugLogLevel.ERROR, e);
1704                }
1705    
1706                return false;
1707              }
1708            }
1709            else
1710            {
1711              return false;
1712            }
1713    
1714    
1715          case PRESENT_TYPE:
1716            return ((attributeType != null) && (type != null) &&
1717                    attributeType.equals(type));
1718    
1719    
1720          case APPROXIMATE_MATCH_TYPE:
1721            if ((attributeType != null) && (type != null) &&
1722                attributeType.equals(type) && (assertionValue != null) &&
1723                (value != null) && (approximateMatchingRule != null))
1724            {
1725              try
1726              {
1727                ByteString nv1 =  approximateMatchingRule.normalizeValue(
1728                        assertionValue.getNormalizedValue());
1729                ByteString nv2 =  approximateMatchingRule.normalizeValue(
1730                        value.getNormalizedValue());
1731    
1732                return approximateMatchingRule.approximatelyMatch(nv1, nv2);
1733              }
1734              catch (Exception e)
1735              {
1736                if (debugEnabled())
1737                {
1738                  TRACER.debugCaught(DebugLogLevel.ERROR, e);
1739                }
1740    
1741                return false;
1742              }
1743            }
1744            else
1745            {
1746              return false;
1747            }
1748    
1749    
1750          case EXTENSIBLE_MATCH_TYPE:
1751            if ((assertionValue == null) || (value == null))
1752            {
1753              return false;
1754            }
1755    
1756            if (attributeType == null)
1757            {
1758              if (matchingRule == null)
1759              {
1760                return false;
1761              }
1762    
1763              try
1764              {
1765                ASN1OctetString nv1 =
1766                     matchingRule.normalizeValue(value.getValue()).
1767                          toASN1OctetString();
1768                ASN1OctetString nv2 =
1769                     matchingRule.normalizeValue(assertionValue.getValue()).
1770                          toASN1OctetString();
1771    
1772                return (matchingRule.valuesMatch(nv1, nv2) == ConditionResult.TRUE);
1773              }
1774              catch (Exception e)
1775              {
1776                if (debugEnabled())
1777                {
1778                  TRACER.debugCaught(DebugLogLevel.ERROR, e);
1779                }
1780    
1781                return false;
1782              }
1783            }
1784            else
1785            {
1786              if ((! attributeType.equals(type)) || (equalityMatchingRule == null))
1787              {
1788                return false;
1789              }
1790    
1791              try
1792              {
1793                return equalityMatchingRule.areEqual(
1794                            assertionValue.getNormalizedValue(),
1795                            value.getNormalizedValue());
1796              }
1797              catch (Exception e)
1798              {
1799                if (debugEnabled())
1800                {
1801                  TRACER.debugCaught(DebugLogLevel.ERROR, e);
1802                }
1803    
1804                return false;
1805              }
1806            }
1807    
1808    
1809          default:
1810            return false;
1811        }
1812      }
1813    
1814    
1815    
1816      /**
1817       * Retrieves a string representation of this matched values filter, as an RFC
1818       * 2254-compliant filter string.
1819       *
1820       * @return  A string representation of this matched values filter.
1821       */
1822      public String toString()
1823      {
1824        StringBuilder buffer = new StringBuilder();
1825        toString(buffer);
1826        return buffer.toString();
1827      }
1828    
1829    
1830    
1831      /**
1832       * Appends a string representation of this matched values filter, as an RFC
1833       * 2254-compliant filter string, to the provided buffer.
1834       *
1835       * @param  buffer  The buffer to which the filter string should be appended.
1836       */
1837      public void toString(StringBuilder buffer)
1838      {
1839        switch (matchType)
1840        {
1841          case EQUALITY_MATCH_TYPE:
1842            buffer.append("(");
1843            buffer.append(rawAttributeType);
1844            buffer.append("=");
1845            RawFilter.valueToFilterString(buffer, rawAssertionValue);
1846            buffer.append(")");
1847            break;
1848    
1849    
1850          case SUBSTRINGS_TYPE:
1851            buffer.append("(");
1852            buffer.append(rawAttributeType);
1853            buffer.append("=");
1854            if (subInitial != null)
1855            {
1856              RawFilter.valueToFilterString(buffer, subInitial);
1857            }
1858    
1859            if (subAny != null)
1860            {
1861              for (ByteString s : subAny)
1862              {
1863                buffer.append("*");
1864                RawFilter.valueToFilterString(buffer, s);
1865              }
1866            }
1867    
1868            buffer.append("*");
1869            if (subFinal != null)
1870            {
1871              RawFilter.valueToFilterString(buffer, subFinal);
1872            }
1873            buffer.append(")");
1874            break;
1875    
1876    
1877          case GREATER_OR_EQUAL_TYPE:
1878            buffer.append("(");
1879            buffer.append(rawAttributeType);
1880            buffer.append(">=");
1881            RawFilter.valueToFilterString(buffer, rawAssertionValue);
1882            buffer.append(")");
1883            break;
1884    
1885    
1886          case LESS_OR_EQUAL_TYPE:
1887            buffer.append("(");
1888            buffer.append(rawAttributeType);
1889            buffer.append("<=");
1890            RawFilter.valueToFilterString(buffer, rawAssertionValue);
1891            buffer.append(")");
1892            break;
1893    
1894    
1895          case PRESENT_TYPE:
1896            buffer.append("(");
1897            buffer.append(rawAttributeType);
1898            buffer.append("=*)");
1899            break;
1900    
1901    
1902          case APPROXIMATE_MATCH_TYPE:
1903            buffer.append("(");
1904            buffer.append(rawAttributeType);
1905            buffer.append("~=");
1906            RawFilter.valueToFilterString(buffer, rawAssertionValue);
1907            buffer.append(")");
1908            break;
1909    
1910    
1911          case EXTENSIBLE_MATCH_TYPE:
1912            buffer.append("(");
1913    
1914            if (rawAttributeType != null)
1915            {
1916              buffer.append(rawAttributeType);
1917            }
1918    
1919            if (matchingRuleID != null)
1920            {
1921              buffer.append(":");
1922              buffer.append(matchingRuleID);
1923            }
1924    
1925            buffer.append(":=");
1926            RawFilter.valueToFilterString(buffer, rawAssertionValue);
1927            buffer.append(")");
1928            break;
1929        }
1930      }
1931    }
1932