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.protocols.ldap;
028 import org.opends.messages.Message;
029
030
031
032 import java.util.ArrayList;
033 import java.util.Iterator;
034 import java.util.LinkedHashSet;
035
036 import org.opends.server.protocols.asn1.ASN1Boolean;
037 import org.opends.server.protocols.asn1.ASN1Element;
038 import org.opends.server.protocols.asn1.ASN1Enumerated;
039 import org.opends.server.protocols.asn1.ASN1Integer;
040 import org.opends.server.protocols.asn1.ASN1OctetString;
041 import org.opends.server.protocols.asn1.ASN1Sequence;
042 import org.opends.server.types.DebugLogLevel;
043 import org.opends.server.types.DereferencePolicy;
044 import org.opends.server.types.LDAPException;
045 import org.opends.server.types.SearchScope;
046
047 import static org.opends.server.loggers.debug.DebugLogger.*;
048 import org.opends.server.loggers.debug.DebugTracer;
049 import static org.opends.messages.ProtocolMessages.*;
050 import static org.opends.server.protocols.ldap.LDAPConstants.*;
051 import static org.opends.server.protocols.ldap.LDAPResultCode.*;
052 import static org.opends.server.util.ServerConstants.*;
053
054
055
056 /**
057 * This class defines the structures and methods for an LDAP search request
058 * protocol op, which is used to locate entries based on a set of criteria.
059 */
060 public class SearchRequestProtocolOp
061 extends ProtocolOp
062 {
063 /**
064 * The tracer object for the debug logger.
065 */
066 private static final DebugTracer TRACER = getTracer();
067
068 // The typesOnly flag for this search request.
069 private boolean typesOnly;
070
071 // The alias dereferencing policy for this search request.
072 private DereferencePolicy dereferencePolicy;
073
074 // The base DN for this search request.
075 private ASN1OctetString baseDN;
076
077 // The size limit for this search request.
078 private int sizeLimit;
079
080 // The time limit for this search request.
081 private int timeLimit;
082
083 // The filter for this search request.
084 private LDAPFilter filter;
085
086 // The set of requested attributes for this search request.
087 private LinkedHashSet<String> attributes;
088
089 // The scope for this search request.
090 private SearchScope scope;
091
092
093
094 /**
095 * Creates a new search request protocol op with the provided information.
096 *
097 * @param baseDN The base DN for this search request.
098 * @param scope The scope for this search request.
099 * @param dereferencePolicy The alias dereferencing policy for this search
100 * request.
101 * @param sizeLimit The size limit for this search request.
102 * @param timeLimit The time limit for this search request.
103 * @param typesOnly The typesOnly flag for this search request.
104 * @param filter The filter for this search request.
105 * @param attributes The set of requested attributes for this search
106 * request.
107 */
108 public SearchRequestProtocolOp(ASN1OctetString baseDN, SearchScope scope,
109 DereferencePolicy dereferencePolicy,
110 int sizeLimit, int timeLimit,
111 boolean typesOnly, LDAPFilter filter,
112 LinkedHashSet<String> attributes)
113 {
114 this.baseDN = baseDN;
115 this.scope = scope;
116 this.dereferencePolicy = dereferencePolicy;
117 this.sizeLimit = sizeLimit;
118 this.timeLimit = timeLimit;
119 this.typesOnly = typesOnly;
120 this.filter = filter;
121
122 if (attributes == null)
123 {
124 this.attributes = new LinkedHashSet<String>(0);
125 }
126 else
127 {
128 this.attributes = attributes;
129 }
130 }
131
132
133
134 /**
135 * Retrieves the base DN for this search request.
136 *
137 * @return The base DN for this search request.
138 */
139 public ASN1OctetString getBaseDN()
140 {
141 return baseDN;
142 }
143
144
145
146 /**
147 * Specifies the base DN for this search request.
148 *
149 * @param baseDN The base DN for this search request.
150 */
151 public void setBaseDN(ASN1OctetString baseDN)
152 {
153 this.baseDN = baseDN;
154 }
155
156
157
158 /**
159 * Retrieves the scope for this search request.
160 *
161 * @return The scope for this search request.
162 */
163 public SearchScope getScope()
164 {
165 return scope;
166 }
167
168
169
170 /**
171 * Specifies the scope for this search request.
172 *
173 * @param scope The scope for this search request.
174 */
175 public void setScope(SearchScope scope)
176 {
177 this.scope = scope;
178 }
179
180
181
182 /**
183 * Retrieves the alias dereferencing policy for this search request.
184 *
185 * @return The alias dereferencing policy for this search request.
186 */
187 public DereferencePolicy getDereferencePolicy()
188 {
189 return dereferencePolicy;
190 }
191
192
193
194 /**
195 * Specifies the alias dereferencing policy for this search request.
196 *
197 * @param dereferencePolicy The alias dereferencing policy for this search
198 * request.
199 */
200 public void setDereferencePolicy(DereferencePolicy dereferencePolicy)
201 {
202 this.dereferencePolicy = dereferencePolicy;
203 }
204
205
206
207 /**
208 * Retrieves the size limit for this search request.
209 *
210 * @return The size limit for this search request.
211 */
212 public int getSizeLimit()
213 {
214 return sizeLimit;
215 }
216
217
218
219 /**
220 * Specifies the size limit for this search request.
221 *
222 * @param sizeLimit The size limit for this search request.
223 */
224 public void setSizeLimit(int sizeLimit)
225 {
226 this.sizeLimit = sizeLimit;
227 }
228
229
230
231 /**
232 * Retrieves the time limit for this search request.
233 *
234 * @return The time limit for this search request.
235 */
236 public int getTimeLimit()
237 {
238 return timeLimit;
239 }
240
241
242
243 /**
244 * Specifies the time limit for this search request.
245 *
246 * @param timeLimit The time limit for this search request.
247 */
248 public void setTimeLimit(int timeLimit)
249 {
250 this.timeLimit = timeLimit;
251 }
252
253
254
255 /**
256 * Retrieves the value of the typesOnly flag for this search request.
257 *
258 * @return The value of tye typesOnly flag for this search request.
259 */
260 public boolean getTypesOnly()
261 {
262 return typesOnly;
263 }
264
265
266
267 /**
268 * Specifies the value of the typesOnly flag for this search request.
269 *
270 * @param typesOnly The value of the typesOnly flag for this search request.
271 */
272 public void setTypesOnly(boolean typesOnly)
273 {
274 this.typesOnly = typesOnly;
275 }
276
277
278
279 /**
280 * Retrieves the filter for this search request.
281 *
282 * @return The filter for this search request.
283 */
284 public LDAPFilter getFilter()
285 {
286 return filter;
287 }
288
289
290
291 /**
292 * Specifies the filter for this search request.
293 *
294 * @param filter The filter for this search request.
295 */
296 public void setFilter(LDAPFilter filter)
297 {
298 this.filter = filter;
299 }
300
301
302
303 /**
304 * Retrieves the set of requested attributes for this search request. The
305 * returned list may be modified by the caller.
306 *
307 * @return The set of requested attributes for this search request.
308 */
309 public LinkedHashSet<String> getAttributes()
310 {
311 return attributes;
312 }
313
314
315
316 /**
317 * Specifies the set of requested attributes for this search request.
318 *
319 * @param attributes The set of requested attributes for this search
320 * request.
321 */
322 public void setAttributes(LinkedHashSet<String> attributes)
323 {
324 if (attributes == null)
325 {
326 this.attributes.clear();
327 }
328 else
329 {
330 this.attributes = attributes;
331 }
332 }
333
334
335
336 /**
337 * Retrieves the BER type for this protocol op.
338 *
339 * @return The BER type for this protocol op.
340 */
341 public byte getType()
342 {
343 return OP_TYPE_SEARCH_REQUEST;
344 }
345
346
347
348 /**
349 * Retrieves the name for this protocol op type.
350 *
351 * @return The name for this protocol op type.
352 */
353 public String getProtocolOpName()
354 {
355 return "Search Request";
356 }
357
358
359
360 /**
361 * Encodes this protocol op to an ASN.1 element suitable for including in an
362 * LDAP message.
363 *
364 * @return The ASN.1 element containing the encoded protocol op.
365 */
366 public ASN1Element encode()
367 {
368 ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(8);
369 elements.add(baseDN);
370 elements.add(new ASN1Enumerated(scope.intValue()));
371 elements.add(new ASN1Enumerated(dereferencePolicy.intValue()));
372 elements.add(new ASN1Integer(sizeLimit));
373 elements.add(new ASN1Integer(timeLimit));
374 elements.add(new ASN1Boolean(typesOnly));
375 elements.add(filter.encode());
376
377 ArrayList<ASN1Element> attrElements =
378 new ArrayList<ASN1Element>(attributes.size());
379 for (String attribute : attributes)
380 {
381 attrElements.add(new ASN1OctetString(attribute));
382 }
383 elements.add(new ASN1Sequence(attrElements));
384
385 return new ASN1Sequence(OP_TYPE_SEARCH_REQUEST, elements);
386 }
387
388
389
390 /**
391 * Decodes the provided ASN.1 element as an LDAP search request protocol op.
392 *
393 * @param element The ASN.1 element to decode.
394 *
395 * @return The decoded LDAP search request protocol op.
396 *
397 * @throws LDAPException If a problem occurs while decoding the provided
398 * ASN.1 element as an LDAP search request protocol
399 * op.
400 */
401 public static SearchRequestProtocolOp decodeSearchRequest(ASN1Element element)
402 throws LDAPException
403 {
404 ArrayList<ASN1Element> elements;
405 try
406 {
407 elements = element.decodeAsSequence().elements();
408 }
409 catch (Exception e)
410 {
411 if (debugEnabled())
412 {
413 TRACER.debugCaught(DebugLogLevel.ERROR, e);
414 }
415
416 Message message =
417 ERR_LDAP_SEARCH_REQUEST_DECODE_SEQUENCE.get(String.valueOf(e));
418 throw new LDAPException(PROTOCOL_ERROR, message, e);
419 }
420
421
422 int numElements = elements.size();
423 if (numElements != 8)
424 {
425 Message message =
426 ERR_LDAP_SEARCH_REQUEST_DECODE_INVALID_ELEMENT_COUNT.get(numElements);
427 throw new LDAPException(PROTOCOL_ERROR, message);
428 }
429
430
431 ASN1OctetString baseDN;
432 try
433 {
434 baseDN = elements.get(0).decodeAsOctetString();
435 }
436 catch (Exception e)
437 {
438 if (debugEnabled())
439 {
440 TRACER.debugCaught(DebugLogLevel.ERROR, e);
441 }
442
443 Message message =
444 ERR_LDAP_SEARCH_REQUEST_DECODE_BASE.get(String.valueOf(e));
445 throw new LDAPException(PROTOCOL_ERROR, message, e);
446 }
447
448
449 SearchScope scope;
450 try
451 {
452 switch (elements.get(1).decodeAsEnumerated().intValue())
453 {
454 case SCOPE_BASE_OBJECT:
455 scope = SearchScope.BASE_OBJECT;
456 break;
457 case SCOPE_SINGLE_LEVEL:
458 scope = SearchScope.SINGLE_LEVEL;
459 break;
460 case SCOPE_WHOLE_SUBTREE:
461 scope = SearchScope.WHOLE_SUBTREE;
462 break;
463 case SCOPE_SUBORDINATE_SUBTREE:
464 scope = SearchScope.SUBORDINATE_SUBTREE;
465 break;
466 default:
467 int scopeValue = elements.get(1).decodeAsEnumerated().intValue();
468 Message message =
469 ERR_LDAP_SEARCH_REQUEST_DECODE_INVALID_SCOPE.get(scopeValue);
470 throw new LDAPException(PROTOCOL_ERROR, message);
471 }
472 }
473 catch (LDAPException le)
474 {
475 throw le;
476 }
477 catch (Exception e)
478 {
479 if (debugEnabled())
480 {
481 TRACER.debugCaught(DebugLogLevel.ERROR, e);
482 }
483
484 Message message =
485 ERR_LDAP_SEARCH_REQUEST_DECODE_SCOPE.get(String.valueOf(e));
486 throw new LDAPException(PROTOCOL_ERROR, message, e);
487 }
488
489
490 DereferencePolicy dereferencePolicy;
491 try
492 {
493 switch (elements.get(2).decodeAsEnumerated().intValue())
494 {
495 case DEREF_NEVER:
496 dereferencePolicy = DereferencePolicy.NEVER_DEREF_ALIASES;
497 break;
498 case DEREF_IN_SEARCHING:
499 dereferencePolicy = DereferencePolicy.DEREF_IN_SEARCHING;
500 break;
501 case DEREF_FINDING_BASE:
502 dereferencePolicy = DereferencePolicy.DEREF_FINDING_BASE_OBJECT;
503 break;
504 case DEREF_ALWAYS:
505 dereferencePolicy = DereferencePolicy.DEREF_ALWAYS;
506 break;
507 default:
508 int derefValue = elements.get(2).decodeAsEnumerated().intValue();
509 Message message =
510 ERR_LDAP_SEARCH_REQUEST_DECODE_INVALID_DEREF.get(derefValue);
511 throw new LDAPException(PROTOCOL_ERROR, message);
512 }
513 }
514 catch (LDAPException le)
515 {
516 throw le;
517 }
518 catch (Exception e)
519 {
520 if (debugEnabled())
521 {
522 TRACER.debugCaught(DebugLogLevel.ERROR, e);
523 }
524
525 Message message =
526 ERR_LDAP_SEARCH_REQUEST_DECODE_DEREF.get(String.valueOf(e));
527 throw new LDAPException(PROTOCOL_ERROR, message, e);
528 }
529
530
531 int sizeLimit;
532 try
533 {
534 sizeLimit = elements.get(3).decodeAsInteger().intValue();
535 }
536 catch (Exception e)
537 {
538 if (debugEnabled())
539 {
540 TRACER.debugCaught(DebugLogLevel.ERROR, e);
541 }
542
543 Message message =
544 ERR_LDAP_SEARCH_REQUEST_DECODE_SIZE_LIMIT.get(String.valueOf(e));
545 throw new LDAPException(PROTOCOL_ERROR, message, e);
546 }
547
548
549 int timeLimit;
550 try
551 {
552 timeLimit = elements.get(4).decodeAsInteger().intValue();
553 }
554 catch (Exception e)
555 {
556 if (debugEnabled())
557 {
558 TRACER.debugCaught(DebugLogLevel.ERROR, e);
559 }
560
561 Message message =
562 ERR_LDAP_SEARCH_REQUEST_DECODE_TIME_LIMIT.get(String.valueOf(e));
563 throw new LDAPException(PROTOCOL_ERROR, message, e);
564 }
565
566
567 boolean typesOnly;
568 try
569 {
570 typesOnly = elements.get(5).decodeAsBoolean().booleanValue();
571 }
572 catch (Exception e)
573 {
574 if (debugEnabled())
575 {
576 TRACER.debugCaught(DebugLogLevel.ERROR, e);
577 }
578
579 Message message =
580 ERR_LDAP_SEARCH_REQUEST_DECODE_TYPES_ONLY.get(String.valueOf(e));
581 throw new LDAPException(PROTOCOL_ERROR, message, e);
582 }
583
584
585 LDAPFilter filter;
586 try
587 {
588 filter = LDAPFilter.decode(elements.get(6));
589 }
590 catch (Exception e)
591 {
592 if (debugEnabled())
593 {
594 TRACER.debugCaught(DebugLogLevel.ERROR, e);
595 }
596
597 Message message =
598 ERR_LDAP_SEARCH_REQUEST_DECODE_FILTER.get(String.valueOf(e));
599 throw new LDAPException(PROTOCOL_ERROR, message, e);
600 }
601
602
603 LinkedHashSet<String> attributes;
604 try
605 {
606 ArrayList<ASN1Element> attrElements =
607 elements.get(7).decodeAsSequence().elements();
608 attributes = new LinkedHashSet<String>(attrElements.size());
609 for (ASN1Element e: attrElements)
610 {
611 attributes.add(e.decodeAsOctetString().stringValue());
612 }
613 }
614 catch (Exception e)
615 {
616 if (debugEnabled())
617 {
618 TRACER.debugCaught(DebugLogLevel.ERROR, e);
619 }
620
621 Message message =
622 ERR_LDAP_SEARCH_REQUEST_DECODE_ATTRIBUTES.get(String.valueOf(e));
623 throw new LDAPException(PROTOCOL_ERROR, message, e);
624 }
625
626
627 return new SearchRequestProtocolOp(baseDN, scope, dereferencePolicy,
628 sizeLimit, timeLimit, typesOnly, filter,
629 attributes);
630 }
631
632
633
634 /**
635 * Appends a string representation of this LDAP protocol op to the provided
636 * buffer.
637 *
638 * @param buffer The buffer to which the string should be appended.
639 */
640 public void toString(StringBuilder buffer)
641 {
642 buffer.append("SearchRequest(baseDN=");
643 baseDN.toString(buffer);
644 buffer.append(", scope=");
645 buffer.append(String.valueOf(scope));
646 buffer.append(", derefPolicy=");
647 buffer.append(String.valueOf(dereferencePolicy));
648 buffer.append(", sizeLimit=");
649 buffer.append(sizeLimit);
650 buffer.append(", timeLimit=");
651 buffer.append(timeLimit);
652 buffer.append(", typesOnly=");
653 buffer.append(typesOnly);
654 buffer.append(", filter=");
655 filter.toString(buffer);
656 buffer.append(", attributes={");
657
658 if ((attributes != null) && (! attributes.isEmpty()))
659 {
660 Iterator<String> iterator = attributes.iterator();
661 buffer.append(iterator.next());
662
663 while (iterator.hasNext())
664 {
665 buffer.append(", ");
666 buffer.append(iterator.next());
667 }
668 }
669
670 buffer.append("})");
671 }
672
673
674
675 /**
676 * Appends a multi-line string representation of this LDAP protocol op to the
677 * provided buffer.
678 *
679 * @param buffer The buffer to which the information should be appended.
680 * @param indent The number of spaces from the margin that the lines should
681 * be indented.
682 */
683 public void toString(StringBuilder buffer, int indent)
684 {
685 StringBuilder indentBuf = new StringBuilder(indent);
686 for (int i=0 ; i < indent; i++)
687 {
688 indentBuf.append(' ');
689 }
690
691 buffer.append(indentBuf);
692 buffer.append("Search Request");
693 buffer.append(EOL);
694
695 buffer.append(indentBuf);
696 buffer.append(" Base DN: ");
697 baseDN.toString(buffer);
698 buffer.append(EOL);
699
700 buffer.append(indentBuf);
701 buffer.append(" Scope: ");
702 buffer.append(String.valueOf(scope));
703 buffer.append(EOL);
704
705 buffer.append(indentBuf);
706 buffer.append(" Dereference Policy: ");
707 buffer.append(String.valueOf(dereferencePolicy));
708 buffer.append(EOL);
709
710 buffer.append(indentBuf);
711 buffer.append(" Size Limit: ");
712 buffer.append(sizeLimit);
713 buffer.append(EOL);
714
715 buffer.append(indentBuf);
716 buffer.append(" Time Limit: ");
717 buffer.append(timeLimit);
718 buffer.append(EOL);
719
720 buffer.append(indentBuf);
721 buffer.append(" Types Only: ");
722 buffer.append(typesOnly);
723 buffer.append(EOL);
724
725 buffer.append(indentBuf);
726 buffer.append(" Filter: ");
727 filter.toString(buffer);
728 buffer.append(EOL);
729
730 buffer.append(indentBuf);
731 buffer.append(" Attributes:");
732 buffer.append(EOL);
733
734 if (attributes != null)
735 {
736 for (String attribute : attributes)
737 {
738 buffer.append(indentBuf);
739 buffer.append(" ");
740 buffer.append(attribute);
741 buffer.append(EOL);
742 }
743 }
744 }
745 }
746