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.types;
028 import org.opends.messages.Message;
029
030
031
032 import java.util.ArrayList;
033
034 import org.opends.server.protocols.asn1.ASN1Boolean;
035 import org.opends.server.protocols.asn1.ASN1Element;
036 import org.opends.server.protocols.asn1.ASN1OctetString;
037 import org.opends.server.protocols.asn1.ASN1Sequence;
038 import org.opends.server.protocols.asn1.ASN1Set;
039 import org.opends.server.protocols.ldap.LDAPFilter;
040
041 import static org.opends.server.loggers.debug.DebugLogger.*;
042 import org.opends.server.loggers.debug.DebugTracer;
043 import static org.opends.messages.ProtocolMessages.*;
044 import static org.opends.server.protocols.ldap.LDAPConstants.*;
045 import static org.opends.server.protocols.ldap.LDAPResultCode.*;
046 import static org.opends.server.util.StaticUtils.*;
047
048
049
050 /**
051 * This class defines the data structures and methods to use when
052 * interacting with a raw search filter, which defines a set of
053 * criteria for locating entries in a search request.
054 */
055 @org.opends.server.types.PublicAPI(
056 stability=org.opends.server.types.StabilityLevel.UNCOMMITTED,
057 mayInstantiate=true,
058 mayExtend=false,
059 mayInvoke=true)
060 public abstract class RawFilter
061 {
062 /**
063 * The tracer object for the debug logger.
064 */
065 private static final DebugTracer TRACER = getTracer();
066
067 /**
068 * Creates a new LDAP filter from the provided filter string.
069 *
070 * @param filterString The filter string to use to create this raw
071 * filter.
072 *
073 * @return The raw filter decoded from the provided filter string.
074 *
075 * @throws LDAPException If the provied filter string could not be
076 * decoded as a raw filter.
077 */
078 public static RawFilter create(String filterString)
079 throws LDAPException
080 {
081 return LDAPFilter.decode(filterString);
082 }
083
084
085
086 /**
087 * Creates a new LDAP filter from the provided search filter.
088 *
089 * @param filter The search filter to use to create this raw
090 * filter.
091 *
092 * @return The constructed raw filter.
093 */
094 public static RawFilter create(SearchFilter filter)
095 {
096 return new LDAPFilter(filter);
097 }
098
099
100
101 /**
102 * Creates a new AND search filter with the provided filter
103 * components.
104 *
105 * @param filterComponents The filter components for this AND
106 * filter.
107 *
108 * @return The AND search filter with the provided filter
109 * components.
110 */
111 public static LDAPFilter createANDFilter(ArrayList<RawFilter>
112 filterComponents)
113 {
114 return new LDAPFilter(FilterType.AND, filterComponents, null,
115 null, null, null, null, null, null, false);
116 }
117
118
119
120 /**
121 * Creates a new OR search filter with the provided filter
122 * components.
123 *
124 * @param filterComponents The filter components for this OR
125 * filter.
126 *
127 * @return The OR search filter with the provided filter
128 * components.
129 */
130 public static LDAPFilter createORFilter(ArrayList<RawFilter>
131 filterComponents)
132 {
133 return new LDAPFilter(FilterType.OR, filterComponents, null, null,
134 null, null, null, null, null, false);
135 }
136
137
138
139 /**
140 * Creates a new NOT search filter with the provided filter
141 * component.
142 *
143 * @param notComponent The filter component for this NOT filter.
144 *
145 * @return The NOT search filter with the provided filter
146 * component.
147 */
148 public static LDAPFilter createNOTFilter(RawFilter notComponent)
149 {
150 return new LDAPFilter(FilterType.NOT, null, notComponent, null,
151 null, null, null, null, null, false);
152 }
153
154
155
156 /**
157 * Creates a new equality search filter with the provided
158 * information.
159 *
160 * @param attributeType The attribute type for this equality
161 * filter.
162 * @param assertionValue The assertion value for this equality
163 * filter.
164 *
165 * @return The constructed equality search filter.
166 */
167 public static LDAPFilter createEqualityFilter(String attributeType,
168 ByteString assertionValue)
169 {
170 return new LDAPFilter(FilterType.EQUALITY, null, null,
171 attributeType, assertionValue, null, null,
172 null, null, false);
173 }
174
175
176
177 /**
178 * Creates a new substring search filter with the provided
179 * information.
180 *
181 * @param attributeType The attribute type for this substring
182 * filter.
183 * @param subInitialElement The subInitial element for this
184 * substring filter.
185 * @param subAnyElements The subAny elements for this substring
186 * filter.
187 * @param subFinalElement The subFinal element for this
188 * substring filter.
189 *
190 * @return The constructed substring search filter.
191 */
192 public static LDAPFilter createSubstringFilter(String attributeType,
193 ByteString subInitialElement,
194 ArrayList<ByteString> subAnyElements,
195 ByteString subFinalElement)
196 {
197 return new LDAPFilter(FilterType.SUBSTRING, null, null,
198 attributeType, null, subInitialElement,
199 subAnyElements, subFinalElement, null,
200 false);
201 }
202
203
204
205 /**
206 * Creates a new greater or equal search filter with the provided
207 * information.
208 *
209 * @param attributeType The attribute type for this greater or
210 * equal filter.
211 * @param assertionValue The assertion value for this greater or
212 * equal filter.
213 *
214 * @return The constructed greater or equal search filter.
215 */
216 public static LDAPFilter createGreaterOrEqualFilter(
217 String attributeType,
218 ByteString assertionValue)
219 {
220 return new LDAPFilter(FilterType.GREATER_OR_EQUAL, null, null,
221 attributeType, assertionValue, null, null,
222 null, null, false);
223 }
224
225
226
227 /**
228 * Creates a new less or equal search filter with the provided
229 * information.
230 *
231 * @param attributeType The attribute type for this less or equal
232 * filter.
233 * @param assertionValue The assertion value for this less or
234 * equal filter.
235 *
236 * @return The constructed less or equal search filter.
237 */
238 public static LDAPFilter createLessOrEqualFilter(
239 String attributeType,
240 ByteString assertionValue)
241 {
242 return new LDAPFilter(FilterType.LESS_OR_EQUAL, null, null,
243 attributeType, assertionValue, null, null,
244 null, null, false);
245 }
246
247
248
249 /**
250 * Creates a new presence search filter with the provided attribute
251 * type.
252 *
253 * @param attributeType The attribute type for this presence
254 * filter.
255 *
256 * @return The constructed presence search filter.
257 */
258 public static LDAPFilter createPresenceFilter(String attributeType)
259 {
260 return new LDAPFilter(FilterType.PRESENT, null, null,
261 attributeType, null, null, null, null, null,
262 false);
263 }
264
265
266
267 /**
268 * Creates a new approximate search filter with the provided
269 * information.
270 *
271 * @param attributeType The attribute type for this approximate
272 * filter.
273 * @param assertionValue The assertion value for this approximate
274 * filter.
275 *
276 * @return The constructed approximate search filter.
277 */
278 public static LDAPFilter createApproximateFilter(
279 String attributeType,
280 ByteString assertionValue)
281 {
282 return new LDAPFilter(FilterType.APPROXIMATE_MATCH, null, null,
283 attributeType, assertionValue, null, null,
284 null, null, false);
285 }
286
287
288
289 /**
290 * Creates a new extensible matching search filter with the provided
291 * information.
292 *
293 * @param matchingRuleID The matching rule ID for this extensible
294 * filter.
295 * @param attributeType The attribute type for this extensible
296 * filter.
297 * @param assertionValue The assertion value for this extensible
298 * filter.
299 * @param dnAttributes The dnAttributes flag for this extensible
300 * filter.
301 *
302 * @return The constructed extensible matching search filter.
303 */
304 public static LDAPFilter createExtensibleFilter(
305 String matchingRuleID,
306 String attributeType,
307 ByteString assertionValue,
308 boolean dnAttributes)
309 {
310 return new LDAPFilter(FilterType.EXTENSIBLE_MATCH, null, null,
311 attributeType, assertionValue, null, null,
312 null, matchingRuleID, dnAttributes);
313 }
314
315
316
317 /**
318 * Retrieves the filter type for this search filter.
319 *
320 * @return The filter type for this search filter.
321 */
322 public abstract FilterType getFilterType();
323
324
325
326 /**
327 * Retrieves the set of subordinate filter components for AND or OR
328 * searches. The contents of the returned list may be altered by
329 * the caller.
330 *
331 * @return The set of subordinate filter components for AND and OR
332 * searches, or {@code null} if this is not an AND or OR
333 * search.
334 */
335 public abstract ArrayList<RawFilter> getFilterComponents();
336
337
338
339 /**
340 * Specifies the set of subordinate filter components for AND or OR
341 * searches. This will be ignored for all other filter types.
342 *
343 * @param filterComponents The set of subordinate filter
344 * components for AND or OR searches.
345 */
346 public abstract void setFilterComponents(
347 ArrayList<RawFilter> filterComponents);
348
349
350
351 /**
352 * Retrieves the subordinate filter component for NOT searches.
353 *
354 * @return The subordinate filter component for NOT searches, or
355 * {@code null} if this is not a NOT search.
356 */
357 public abstract RawFilter getNOTComponent();
358
359
360
361 /**
362 * Specifies the subordinate filter component for NOT searches.
363 * This will be ignored for any other type of search.
364 *
365 * @param notComponent The subordinate filter component for NOT
366 * searches.
367 */
368 public abstract void setNOTComponent(RawFilter notComponent);
369
370
371
372 /**
373 * Retrieves the attribute type for this search filter. This will
374 * not be applicable for AND, OR, or NOT filters.
375 *
376 * @return The attribute type for this search filter, or
377 * {@code null} if there is none.
378 */
379 public abstract String getAttributeType();
380
381
382
383 /**
384 * Specifies the attribute type for this search filter. This will
385 * be ignored for AND, OR, and NOT searches.
386 *
387 * @param attributeType The attribute type for this search filter.
388 */
389 public abstract void setAttributeType(String attributeType);
390
391
392
393 /**
394 * Retrieves the assertion value for this search filter. This will
395 * only be applicable for equality, greater or equal, less or equal,
396 * approximate, or extensible matching filters.
397 *
398 * @return The assertion value for this search filter, or
399 * {@code null} if there is none.
400 */
401 public abstract ByteString getAssertionValue();
402
403
404
405 /**
406 * Specifies the assertion value for this search filter. This will
407 * be ignored for types of filters that do not have an assertion
408 * value.
409 *
410 * @param assertionValue The assertion value for this search
411 * filter.
412 */
413 public abstract void setAssertionValue(ByteString assertionValue);
414
415
416
417 /**
418 * Retrieves the subInitial component for this substring filter.
419 * This is only applicable for substring search filters, but even
420 * substring filters might not have a value for this component.
421 *
422 * @return The subInitial component for this substring filter, or
423 * {@code null} if there is none.
424 */
425 public abstract ByteString getSubInitialElement();
426
427
428
429 /**
430 * Specifies the subInitial element for this substring filter.
431 * This will be ignored for all other types of filters.
432 *
433 * @param subInitialElement The subInitial element for this
434 * substring filter.
435 */
436 public abstract void setSubInitialElement(
437 ByteString subInitialElement);
438
439
440
441 /**
442 * Retrieves the set of subAny elements for this substring filter.
443 * This is only applicable for substring search filters, and even
444 * then may be {@code null} or empty for some substring filters.
445 *
446 * @return The set of subAny elements for this substring filter, or
447 * {@code null} if there are none.
448 */
449 public abstract ArrayList<ByteString> getSubAnyElements();
450
451
452
453 /**
454 * Specifies the set of subAny values for this substring filter.
455 * This will be ignored for other filter types.
456 *
457 * @param subAnyElements The set of subAny elements for this
458 * substring filter.
459 */
460 public abstract void setSubAnyElements(ArrayList<ByteString>
461 subAnyElements);
462
463
464
465 /**
466 * Retrieves the subFinal element for this substring filter. This
467 * is not applicable for any other filter type, and may not be
468 * provided even for some substring filters.
469 *
470 * @return The subFinal element for this substring filter, or
471 * {@code null} if there is none.
472 */
473 public abstract ByteString getSubFinalElement();
474
475
476
477 /**
478 * Specifies the subFinal element for this substring filter. This
479 * will be ignored for all other filter types.
480 *
481 * @param subFinalElement The subFinal element for this substring
482 * filter.
483 */
484 public abstract void setSubFinalElement(ByteString subFinalElement);
485
486
487
488 /**
489 * Retrieves the matching rule ID for this extensible match filter.
490 * This is not applicable for any other type of filter and may not
491 * be included in some extensible matching filters.
492 *
493 * @return The matching rule ID for this extensible match filter,
494 * or {@code null} if there is none.
495 */
496 public abstract String getMatchingRuleID();
497
498
499
500 /**
501 * Specifies the matching rule ID for this extensible match filter.
502 * It will be ignored for all other filter types.
503 *
504 * @param matchingRuleID The matching rule ID for this extensible
505 * match filter.
506 */
507 public abstract void setMatchingRuleID(String matchingRuleID);
508
509
510
511 /**
512 * Retrieves the value of the DN attributes flag for this extensible
513 * match filter, which indicates whether to perform matching on the
514 * components of the DN. This does not apply for any other type of
515 * filter.
516 *
517 * @return The value of the DN attributes flag for this
518 * extensibleMatch filter.
519 */
520 public abstract boolean getDNAttributes();
521
522
523
524 /**
525 * Specifies the value of the DN attributes flag for this extensible
526 * match filter. It will be ignored for all other filter types.
527 *
528 * @param dnAttributes The value of the DN attributes flag for
529 * this extensible match filter.
530 */
531 public abstract void setDNAttributes(boolean dnAttributes);
532
533
534
535 /**
536 * Encodes this search filter to an ASN.1 element.
537 *
538 * @return The ASN.1 element containing the encoded search filter.
539 */
540 public final ASN1Element encode()
541 {
542 FilterType filterType = getFilterType();
543 switch (filterType)
544 {
545 case AND:
546 case OR:
547 ArrayList<RawFilter> filterComponents = getFilterComponents();
548 ArrayList<ASN1Element> elements =
549 new ArrayList<ASN1Element>(filterComponents.size());
550 for (RawFilter f : filterComponents)
551 {
552 elements.add(f.encode());
553 }
554 return new ASN1Set(filterType.getBERType(), elements);
555 case NOT:
556 return new ASN1Element(filterType.getBERType(),
557 getNOTComponent().encode().encode());
558 case EQUALITY:
559 case GREATER_OR_EQUAL:
560 case LESS_OR_EQUAL:
561 case APPROXIMATE_MATCH:
562 String attributeType = getAttributeType();
563 ByteString assertionValue = getAssertionValue();
564 elements = new ArrayList<ASN1Element>(2);
565 elements.add(new ASN1OctetString(attributeType));
566 elements.add(assertionValue.toASN1OctetString());
567 return new ASN1Sequence(filterType.getBERType(), elements);
568 case SUBSTRING:
569 attributeType = getAttributeType();
570 elements = new ArrayList<ASN1Element>(2);
571 elements.add(new ASN1OctetString(attributeType));
572
573 ByteString subInitialElement = getSubInitialElement();
574 ArrayList<ASN1Element> subElements =
575 new ArrayList<ASN1Element>();
576 if (subInitialElement != null)
577 {
578 ASN1OctetString subInitialOS =
579 subInitialElement.toASN1OctetString();
580 subInitialOS.setType(TYPE_SUBINITIAL);
581 subElements.add(subInitialOS);
582 }
583
584 ArrayList<ByteString> subAnyElements = getSubAnyElements();
585 if ((subAnyElements != null) && (! subAnyElements.isEmpty()))
586 {
587 for (ByteString s : subAnyElements)
588 {
589 ASN1OctetString os = s.toASN1OctetString();
590 os.setType(TYPE_SUBANY);
591 subElements.add(os);
592 }
593 }
594
595 ByteString subFinalElement = getSubFinalElement();
596 if (subFinalElement != null)
597 {
598 ASN1OctetString subFinalOS =
599 subFinalElement.toASN1OctetString();
600 subFinalOS.setType(TYPE_SUBFINAL);
601 subElements.add(subFinalOS);
602 }
603
604 elements.add(new ASN1Sequence(subElements));
605 return new ASN1Sequence(filterType.getBERType(), elements);
606 case PRESENT:
607 return new ASN1OctetString(filterType.getBERType(),
608 getAttributeType());
609 case EXTENSIBLE_MATCH:
610 elements = new ArrayList<ASN1Element>(4);
611
612 String matchingRuleID = getMatchingRuleID();
613 if (matchingRuleID != null)
614 {
615 elements.add(new ASN1OctetString(TYPE_MATCHING_RULE_ID,
616 matchingRuleID));
617 }
618
619 attributeType = getAttributeType();
620 if (attributeType != null)
621 {
622 elements.add(new ASN1OctetString(TYPE_MATCHING_RULE_TYPE,
623 attributeType));
624 }
625
626 ASN1OctetString assertionValueOS =
627 getAssertionValue().toASN1OctetString();
628 assertionValueOS.setType(TYPE_MATCHING_RULE_VALUE);
629 elements.add(assertionValueOS);
630
631 if (getDNAttributes())
632 {
633 elements.add(new ASN1Boolean(
634 TYPE_MATCHING_RULE_DN_ATTRIBUTES, true));
635 }
636
637 return new ASN1Sequence(filterType.getBERType(), elements);
638 default:
639 if (debugEnabled())
640 {
641 TRACER.debugError("Invalid search filter type: %s",
642 filterType);
643 }
644 return null;
645 }
646 }
647
648
649
650 /**
651 * Decodes the provided ASN.1 element as a raw search filter.
652 *
653 * @param element The ASN.1 element to decode.
654 *
655 * @return The decoded search filter.
656 *
657 * @throws LDAPException If the provided ASN.1 element cannot be
658 * decoded as a raw search filter.
659 */
660 public static LDAPFilter decode(ASN1Element element)
661 throws LDAPException
662 {
663 if (element == null)
664 {
665 Message message = ERR_LDAP_FILTER_DECODE_NULL.get();
666 throw new LDAPException(PROTOCOL_ERROR, message);
667 }
668
669 switch (element.getType())
670 {
671 case TYPE_FILTER_AND:
672 case TYPE_FILTER_OR:
673 return decodeCompoundFilter(element);
674
675 case TYPE_FILTER_NOT:
676 return decodeNotFilter(element);
677
678 case TYPE_FILTER_EQUALITY:
679 case TYPE_FILTER_GREATER_OR_EQUAL:
680 case TYPE_FILTER_LESS_OR_EQUAL:
681 case TYPE_FILTER_APPROXIMATE:
682 return decodeTypeAndValueFilter(element);
683
684 case TYPE_FILTER_SUBSTRING:
685 return decodeSubstringFilter(element);
686
687 case TYPE_FILTER_PRESENCE:
688 return decodePresenceFilter(element);
689
690 case TYPE_FILTER_EXTENSIBLE_MATCH:
691 return decodeExtensibleMatchFilter(element);
692
693 default:
694 Message message = ERR_LDAP_FILTER_DECODE_INVALID_TYPE.get(
695 element.getType());
696 throw new LDAPException(PROTOCOL_ERROR, message);
697 }
698 }
699
700
701
702 /**
703 * Decodes the provided ASN.1 element as a compound filter (i.e.,
704 * one that holds a set of subordinate filter components, like AND
705 * or OR filters).
706 *
707 * @param element the ASN.1 element to decode.
708 *
709 * @return The decoded LDAP search filter.
710 *
711 * @throws LDAPException If a problem occurs while trying to
712 * decode the provided ASN.1 element as a
713 * raw search filter.
714 */
715 private static LDAPFilter decodeCompoundFilter(ASN1Element element)
716 throws LDAPException
717 {
718 FilterType filterType;
719 switch (element.getType())
720 {
721 case TYPE_FILTER_AND:
722 filterType = FilterType.AND;
723 break;
724 case TYPE_FILTER_OR:
725 filterType = FilterType.OR;
726 break;
727 default:
728 // This should never happen.
729 if (debugEnabled())
730 {
731 TRACER.debugError("Invalid filter type %x for a " +
732 "compound filter", element.getType());
733 }
734 filterType = null;
735 }
736
737
738 ArrayList<ASN1Element> elements;
739 try
740 {
741 elements = element.decodeAsSet().elements();
742 }
743 catch (Exception e)
744 {
745 if (debugEnabled())
746 {
747 TRACER.debugCaught(DebugLogLevel.ERROR, e);
748 }
749
750 Message message =
751 ERR_LDAP_FILTER_DECODE_COMPOUND_SET.get(String.valueOf(e));
752 throw new LDAPException(PROTOCOL_ERROR, message, e);
753 }
754
755
756 ArrayList<RawFilter> filterComponents =
757 new ArrayList<RawFilter>(elements.size());
758 try
759 {
760 for (ASN1Element e : elements)
761 {
762 filterComponents.add(LDAPFilter.decode(e));
763 }
764 }
765 catch (LDAPException le)
766 {
767 throw le;
768 }
769 catch (Exception e)
770 {
771 if (debugEnabled())
772 {
773 TRACER.debugCaught(DebugLogLevel.ERROR, e);
774 }
775
776 Message message = ERR_LDAP_FILTER_DECODE_COMPOUND_COMPONENTS.
777 get(String.valueOf(e));
778 throw new LDAPException(PROTOCOL_ERROR, message, e);
779 }
780
781
782 return new LDAPFilter(filterType, filterComponents, null, null,
783 null, null, null, null, null, false);
784 }
785
786
787
788 /**
789 * Decodes the provided ASN.1 element as a NOT filter.
790 *
791 * @param element the ASN.1 element to decode.
792 *
793 * @return The decoded LDAP search filter.
794 *
795 * @throws LDAPException If a problem occurs while trying to
796 * decode the provided ASN.1 element as a
797 * raw search filter.
798 */
799 private static LDAPFilter decodeNotFilter(ASN1Element element)
800 throws LDAPException
801 {
802 ASN1Element notFilterElement;
803 try
804 {
805 notFilterElement = ASN1Element.decode(element.value());
806 }
807 catch (Exception e)
808 {
809 if (debugEnabled())
810 {
811 TRACER.debugCaught(DebugLogLevel.ERROR, e);
812 }
813
814 Message message =
815 ERR_LDAP_FILTER_DECODE_NOT_ELEMENT.get(String.valueOf(e));
816 throw new LDAPException(PROTOCOL_ERROR, message, e);
817 }
818
819
820 RawFilter notComponent;
821 try
822 {
823 notComponent = decode(notFilterElement);
824 }
825 catch (LDAPException le)
826 {
827 throw le;
828 }
829 catch (Exception e)
830 {
831 if (debugEnabled())
832 {
833 TRACER.debugCaught(DebugLogLevel.ERROR, e);
834 }
835
836 Message message =
837 ERR_LDAP_FILTER_DECODE_NOT_COMPONENT.get(String.valueOf(e));
838 throw new LDAPException(PROTOCOL_ERROR, message, e);
839 }
840
841
842 return new LDAPFilter(FilterType.NOT, null, notComponent, null,
843 null, null, null, null, null, false);
844 }
845
846
847
848 /**
849 * Decodes the provided ASN.1 element as a filter containing an
850 * attribute type and an assertion value. This includes equality,
851 * greater or equal, less or equal, and approximate search filters.
852 *
853 * @param element the ASN.1 element to decode.
854 *
855 * @return The decoded LDAP search filter.
856 *
857 * @throws LDAPException If a problem occurs while trying to
858 * decode the provided ASN.1 element as a
859 * raw search filter.
860 */
861 private static LDAPFilter decodeTypeAndValueFilter(
862 ASN1Element element)
863 throws LDAPException
864 {
865 FilterType filterType;
866 switch (element.getType())
867 {
868 case TYPE_FILTER_EQUALITY:
869 filterType = FilterType.EQUALITY;
870 break;
871 case TYPE_FILTER_GREATER_OR_EQUAL:
872 filterType = FilterType.GREATER_OR_EQUAL;
873 break;
874 case TYPE_FILTER_LESS_OR_EQUAL:
875 filterType = FilterType.LESS_OR_EQUAL;
876 break;
877 case TYPE_FILTER_APPROXIMATE:
878 filterType = FilterType.APPROXIMATE_MATCH;
879 break;
880 default:
881 // This should never happen.
882 if (debugEnabled())
883 {
884 TRACER.debugError("Invalid filter type %x for a " +
885 "type-and-value filter", element.getType());
886 }
887 filterType = null;
888 }
889
890
891 ArrayList<ASN1Element> elements;
892 try
893 {
894 elements = element.decodeAsSequence().elements();
895 }
896 catch (Exception e)
897 {
898 if (debugEnabled())
899 {
900 TRACER.debugCaught(DebugLogLevel.ERROR, e);
901 }
902
903 Message message =
904 ERR_LDAP_FILTER_DECODE_TV_SEQUENCE.get(String.valueOf(e));
905 throw new LDAPException(PROTOCOL_ERROR, message, e);
906 }
907
908
909 if (elements.size() != 2)
910 {
911 Message message =
912 ERR_LDAP_FILTER_DECODE_TV_INVALID_ELEMENT_COUNT.
913 get(elements.size());
914 throw new LDAPException(PROTOCOL_ERROR, message);
915 }
916
917
918 String attributeType;
919 try
920 {
921 attributeType =
922 elements.get(0).decodeAsOctetString().stringValue();
923 }
924 catch (Exception e)
925 {
926 if (debugEnabled())
927 {
928 TRACER.debugCaught(DebugLogLevel.ERROR, e);
929 }
930
931 Message message =
932 ERR_LDAP_FILTER_DECODE_TV_TYPE.get(String.valueOf(e));
933 throw new LDAPException(PROTOCOL_ERROR, message, e);
934 }
935
936
937 ByteString assertionValue;
938 try
939 {
940 assertionValue = elements.get(1).decodeAsOctetString();
941 }
942 catch (Exception e)
943 {
944 if (debugEnabled())
945 {
946 TRACER.debugCaught(DebugLogLevel.ERROR, e);
947 }
948
949 Message message =
950 ERR_LDAP_FILTER_DECODE_TV_VALUE.get(String.valueOf(e));
951 throw new LDAPException(PROTOCOL_ERROR, message, e);
952 }
953
954
955 return new LDAPFilter(filterType, null, null, attributeType,
956 assertionValue, null, null, null, null,
957 false);
958 }
959
960
961
962 /**
963 * Decodes the provided ASN.1 element as a substring filter.
964 *
965 * @param element the ASN.1 element to decode.
966 *
967 * @return The decoded LDAP search filter.
968 *
969 * @throws LDAPException If a problem occurs while trying to
970 * decode the provided ASN.1 element as a
971 * raw search filter.
972 */
973 private static LDAPFilter decodeSubstringFilter(ASN1Element element)
974 throws LDAPException
975 {
976 ArrayList<ASN1Element> elements;
977 try
978 {
979 elements = element.decodeAsSequence().elements();
980 }
981 catch (Exception e)
982 {
983 if (debugEnabled())
984 {
985 TRACER.debugCaught(DebugLogLevel.ERROR, e);
986 }
987
988 Message message = ERR_LDAP_FILTER_DECODE_SUBSTRING_SEQUENCE.get(
989 String.valueOf(e));
990 throw new LDAPException(PROTOCOL_ERROR, message, e);
991 }
992
993
994 if (elements.size() != 2)
995 {
996 Message message =
997 ERR_LDAP_FILTER_DECODE_SUBSTRING_INVALID_ELEMENT_COUNT.
998 get(elements.size());
999 throw new LDAPException(PROTOCOL_ERROR, message);
1000 }
1001
1002
1003 String attributeType;
1004 try
1005 {
1006 attributeType =
1007 elements.get(0).decodeAsOctetString().stringValue();
1008 }
1009 catch (Exception e)
1010 {
1011 if (debugEnabled())
1012 {
1013 TRACER.debugCaught(DebugLogLevel.ERROR, e);
1014 }
1015
1016 Message message = ERR_LDAP_FILTER_DECODE_SUBSTRING_TYPE.get(
1017 String.valueOf(e));
1018 throw new LDAPException(PROTOCOL_ERROR, message, e);
1019 }
1020
1021
1022 ArrayList<ASN1Element> subElements;
1023 try
1024 {
1025 subElements = elements.get(1).decodeAsSequence().elements();
1026 }
1027 catch (Exception e)
1028 {
1029 if (debugEnabled())
1030 {
1031 TRACER.debugCaught(DebugLogLevel.ERROR, e);
1032 }
1033
1034 Message message = ERR_LDAP_FILTER_DECODE_SUBSTRING_ELEMENTS.get(
1035 String.valueOf(e));
1036 throw new LDAPException(PROTOCOL_ERROR, message, e);
1037 }
1038
1039
1040 if (subElements.isEmpty())
1041 {
1042 Message message =
1043 ERR_LDAP_FILTER_DECODE_SUBSTRING_NO_SUBELEMENTS.get();
1044 throw new LDAPException(PROTOCOL_ERROR, message);
1045 }
1046
1047
1048 ByteString subInitialElement = null;
1049 ByteString subFinalElement = null;
1050 ArrayList<ByteString> subAnyElements = null;
1051 try
1052 {
1053 for (ASN1Element e : subElements)
1054 {
1055 switch (e.getType())
1056 {
1057 case TYPE_SUBINITIAL:
1058 subInitialElement = e.decodeAsOctetString();
1059 break;
1060 case TYPE_SUBFINAL:
1061 subFinalElement = e.decodeAsOctetString();
1062 break;
1063 case TYPE_SUBANY:
1064 if (subAnyElements == null)
1065 {
1066 subAnyElements = new ArrayList<ByteString>();
1067 }
1068
1069 subAnyElements.add(e.decodeAsOctetString());
1070 break;
1071 default:
1072 Message message =
1073 ERR_LDAP_FILTER_DECODE_SUBSTRING_INVALID_SUBTYPE.
1074 get(e.getType());
1075 throw new LDAPException(PROTOCOL_ERROR, message);
1076 }
1077 }
1078 }
1079 catch (LDAPException le)
1080 {
1081 throw le;
1082 }
1083 catch (Exception e)
1084 {
1085 if (debugEnabled())
1086 {
1087 TRACER.debugCaught(DebugLogLevel.ERROR, e);
1088 }
1089
1090 Message message = ERR_LDAP_FILTER_DECODE_SUBSTRING_VALUES.get(
1091 String.valueOf(e));
1092 throw new LDAPException(PROTOCOL_ERROR, message, e);
1093 }
1094
1095
1096 return new LDAPFilter(FilterType.SUBSTRING, null, null,
1097 attributeType, null, subInitialElement,
1098 subAnyElements, subFinalElement, null,
1099 false);
1100 }
1101
1102
1103
1104 /**
1105 * Decodes the provided ASN.1 element as a presence filter.
1106 *
1107 * @param element the ASN.1 element to decode.
1108 *
1109 * @return The decoded LDAP search filter.
1110 *
1111 * @throws LDAPException If a problem occurs while trying to
1112 * decode the provided ASN.1 element as a
1113 * raw search filter.
1114 */
1115 private static LDAPFilter decodePresenceFilter(ASN1Element element)
1116 throws LDAPException
1117 {
1118 String attributeType;
1119 try
1120 {
1121 attributeType = element.decodeAsOctetString().stringValue();
1122 }
1123 catch (Exception e)
1124 {
1125 if (debugEnabled())
1126 {
1127 TRACER.debugCaught(DebugLogLevel.ERROR, e);
1128 }
1129
1130 Message message =
1131 ERR_LDAP_FILTER_DECODE_PRESENCE_TYPE.get(String.valueOf(e));
1132 throw new LDAPException(PROTOCOL_ERROR, message, e);
1133 }
1134
1135
1136 return new LDAPFilter(FilterType.PRESENT, null, null,
1137 attributeType, null, null, null, null, null,
1138 false);
1139 }
1140
1141
1142
1143 /**
1144 * Decodes the provided ASN.1 element as an extensible match filter.
1145 *
1146 * @param element the ASN.1 element to decode.
1147 *
1148 * @return The decoded LDAP search filter.
1149 *
1150 * @throws LDAPException If a problem occurs while trying to
1151 * decode the provided ASN.1 element as a
1152 * raw search filter.
1153 */
1154 private static LDAPFilter decodeExtensibleMatchFilter(ASN1Element
1155 element)
1156 throws LDAPException
1157 {
1158 ArrayList<ASN1Element> elements;
1159 try
1160 {
1161 elements = element.decodeAsSequence().elements();
1162 }
1163 catch (Exception e)
1164 {
1165 if (debugEnabled())
1166 {
1167 TRACER.debugCaught(DebugLogLevel.ERROR, e);
1168 }
1169
1170 Message message = ERR_LDAP_FILTER_DECODE_EXTENSIBLE_SEQUENCE.
1171 get(String.valueOf(e));
1172 throw new LDAPException(PROTOCOL_ERROR, message, e);
1173 }
1174
1175
1176 ByteString assertionValue = null;
1177 boolean dnAttributes = false;
1178 String attributeType = null;
1179 String matchingRuleID = null;
1180 try
1181 {
1182 for (ASN1Element e : elements)
1183 {
1184 switch (e.getType())
1185 {
1186 case TYPE_MATCHING_RULE_ID:
1187 matchingRuleID = e.decodeAsOctetString().stringValue();
1188 break;
1189 case TYPE_MATCHING_RULE_TYPE:
1190 attributeType = e.decodeAsOctetString().stringValue();
1191 break;
1192 case TYPE_MATCHING_RULE_VALUE:
1193 assertionValue = e.decodeAsOctetString();
1194 break;
1195 case TYPE_MATCHING_RULE_DN_ATTRIBUTES:
1196 dnAttributes = e.decodeAsBoolean().booleanValue();
1197 break;
1198 default:
1199 Message message =
1200 ERR_LDAP_FILTER_DECODE_EXTENSIBLE_INVALID_TYPE.
1201 get(e.getType());
1202 throw new LDAPException(PROTOCOL_ERROR, message);
1203 }
1204 }
1205 }
1206 catch (LDAPException le)
1207 {
1208 throw le;
1209 }
1210 catch (Exception e)
1211 {
1212 if (debugEnabled())
1213 {
1214 TRACER.debugCaught(DebugLogLevel.ERROR, e);
1215 }
1216
1217 Message message = ERR_LDAP_FILTER_DECODE_EXTENSIBLE_ELEMENTS.
1218 get(String.valueOf(e));
1219 throw new LDAPException(PROTOCOL_ERROR, message, e);
1220 }
1221
1222
1223 return new LDAPFilter(FilterType.EXTENSIBLE_MATCH, null, null,
1224 attributeType, assertionValue, null, null,
1225 null, matchingRuleID, dnAttributes);
1226 }
1227
1228
1229
1230 /**
1231 * Converts this raw filter to a search filter that may be used by
1232 * the Directory Server's core processing.
1233 *
1234 * @return The generated search filter.
1235 *
1236 * @throws DirectoryException If a problem occurs while attempting
1237 * to construct the search filter.
1238 */
1239 public abstract SearchFilter toSearchFilter()
1240 throws DirectoryException;
1241
1242
1243
1244 /**
1245 * Retrieves a string representation of this search filter.
1246 *
1247 * @return A string representation of this search filter.
1248 */
1249 public String toString()
1250 {
1251 StringBuilder buffer = new StringBuilder();
1252 toString(buffer);
1253 return buffer.toString();
1254 }
1255
1256
1257
1258 /**
1259 * Appends a string representation of this search filter to the
1260 * provided buffer.
1261 *
1262 * @param buffer The buffer to which the information should be
1263 * appended.
1264 */
1265 public abstract void toString(StringBuilder buffer);
1266
1267
1268
1269 /**
1270 * Appends a properly-cleaned version of the provided value to the
1271 * given buffer so that it can be safely used in string
1272 * representations of this search filter. The formatting changes
1273 * that may be performed will be in compliance with the
1274 * specification in RFC 2254.
1275 *
1276 * @param buffer The buffer to which the "safe" version of the
1277 * value will be appended.
1278 * @param value The value to be appended to the buffer.
1279 */
1280 public static void valueToFilterString(StringBuilder buffer,
1281 ByteString value)
1282 {
1283 if (value == null)
1284 {
1285 return;
1286 }
1287
1288
1289 // Get the binary representation of the value and iterate through
1290 // it to see if there are any unsafe characters. If there are,
1291 // then escape them and replace them with a two-digit hex
1292 // equivalent.
1293 byte[] valueBytes = value.value();
1294 buffer.ensureCapacity(buffer.length() + valueBytes.length);
1295 for (byte b : valueBytes)
1296 {
1297 if (((b & 0x7F) != b) || // Not 7-bit clean
1298 (b <= 0x1F) || // Below the printable character range
1299 (b == 0x28) || // Open parenthesis
1300 (b == 0x29) || // Close parenthesis
1301 (b == 0x2A) || // Asterisk
1302 (b == 0x5C) || // Backslash
1303 (b == 0x7F)) // Delete character
1304 {
1305 buffer.append("\\");
1306 buffer.append(byteToHex(b));
1307 }
1308 else
1309 {
1310 buffer.append((char) b);
1311 }
1312 }
1313 }
1314 }
1315