001 /*
002 * Copyright 2009-2014 UnboundID Corp.
003 * All Rights Reserved.
004 */
005 /*
006 * Copyright (C) 2009-2014 UnboundID Corp.
007 *
008 * This program is free software; you can redistribute it and/or modify
009 * it under the terms of the GNU General Public License (GPLv2 only)
010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
011 * as published by the Free Software Foundation.
012 *
013 * This program is distributed in the hope that it will be useful,
014 * but WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016 * GNU General Public License for more details.
017 *
018 * You should have received a copy of the GNU General Public License
019 * along with this program; if not, see <http://www.gnu.org/licenses>.
020 */
021 package com.unboundid.ldap.protocol;
022
023
024
025 import java.util.ArrayList;
026 import java.util.Collections;
027 import java.util.Iterator;
028 import java.util.List;
029
030 import com.unboundid.asn1.ASN1Boolean;
031 import com.unboundid.asn1.ASN1Buffer;
032 import com.unboundid.asn1.ASN1BufferSequence;
033 import com.unboundid.asn1.ASN1Element;
034 import com.unboundid.asn1.ASN1Enumerated;
035 import com.unboundid.asn1.ASN1Integer;
036 import com.unboundid.asn1.ASN1OctetString;
037 import com.unboundid.asn1.ASN1Sequence;
038 import com.unboundid.asn1.ASN1StreamReader;
039 import com.unboundid.asn1.ASN1StreamReaderSequence;
040 import com.unboundid.ldap.sdk.Control;
041 import com.unboundid.ldap.sdk.DereferencePolicy;
042 import com.unboundid.ldap.sdk.Filter;
043 import com.unboundid.ldap.sdk.LDAPException;
044 import com.unboundid.ldap.sdk.ResultCode;
045 import com.unboundid.ldap.sdk.SearchRequest;
046 import com.unboundid.ldap.sdk.SearchScope;
047 import com.unboundid.util.InternalUseOnly;
048
049 import static com.unboundid.ldap.protocol.ProtocolMessages.*;
050 import static com.unboundid.util.Debug.*;
051 import static com.unboundid.util.StaticUtils.*;
052
053
054
055 /**
056 * This class provides an implementation of an LDAP search request protocol op.
057 */
058 @InternalUseOnly()
059 public final class SearchRequestProtocolOp
060 implements ProtocolOp
061 {
062 /**
063 * The serial version UID for this serializable class.
064 */
065 private static final long serialVersionUID = -8521750809606744181L;
066
067
068
069 // The typesOnly flag for this search request.
070 private final boolean typesOnly;
071
072 // The dereference policy for this search request.
073 private final DereferencePolicy derefPolicy;
074
075 // The filter for this search request.
076 private final Filter filter;
077
078 // The size limit for this search request.
079 private final int sizeLimit;
080
081 // The time limit for this search request.
082 private final int timeLimit;
083
084 // The set of attributes for this search request.
085 private final List<String> attributes;
086
087 // The scope for this search request.
088 private final SearchScope scope;
089
090 // The base DN for this search request.
091 private final String baseDN;
092
093
094
095 /**
096 * Creates a new search request protocol op with the provided information.
097 *
098 * @param baseDN The base DN for this search request.
099 * @param scope The scope for this search request.
100 * @param derefPolicy The policy to use for aliases encountered during the
101 * search.
102 * @param sizeLimit The maximum number of entries to return for the
103 * search, or zero for no limit.
104 * @param timeLimit The maximum length of time to spend processing the
105 * search, or zero for no limit.
106 * @param typesOnly Indicates whether to return only attribute types or
107 * both types and values.
108 * @param filter The filter for this search request.
109 * @param attributes The names of attributes to include in matching
110 * entries.
111 */
112 public SearchRequestProtocolOp(final String baseDN, final SearchScope scope,
113 final DereferencePolicy derefPolicy, final int sizeLimit,
114 final int timeLimit, final boolean typesOnly, final Filter filter,
115 final List<String> attributes)
116 {
117 this.scope = scope;
118 this.derefPolicy = derefPolicy;
119 this.typesOnly = typesOnly;
120 this.filter = filter;
121
122 if (baseDN == null)
123 {
124 this.baseDN = "";
125 }
126 else
127 {
128 this.baseDN = baseDN;
129 }
130
131 if (sizeLimit > 0)
132 {
133 this.sizeLimit = sizeLimit;
134 }
135 else
136 {
137 this.sizeLimit = 0;
138 }
139
140 if (timeLimit > 0)
141 {
142 this.timeLimit = timeLimit;
143 }
144 else
145 {
146 this.timeLimit = 0;
147 }
148
149 if (attributes == null)
150 {
151 this.attributes = Collections.emptyList();
152 }
153 else
154 {
155 this.attributes = Collections.unmodifiableList(attributes);
156 }
157 }
158
159
160
161 /**
162 * Creates a new search request protocol op from the provided search request
163 * object.
164 *
165 * @param request The search request object to use to create this protocol
166 * op.
167 */
168 public SearchRequestProtocolOp(final SearchRequest request)
169 {
170 baseDN = request.getBaseDN();
171 scope = request.getScope();
172 derefPolicy = request.getDereferencePolicy();
173 sizeLimit = request.getSizeLimit();
174 timeLimit = request.getTimeLimitSeconds();
175 typesOnly = request.typesOnly();
176 filter = request.getFilter();
177 attributes = request.getAttributeList();
178 }
179
180
181
182 /**
183 * Creates a new search request protocol op read from the provided ASN.1
184 * stream reader.
185 *
186 * @param reader The ASN.1 stream reader from which to read the search
187 * request protocol op.
188 *
189 * @throws LDAPException If a problem occurs while reading or parsing the
190 * search request.
191 */
192 SearchRequestProtocolOp(final ASN1StreamReader reader)
193 throws LDAPException
194 {
195 try
196 {
197 reader.beginSequence();
198 baseDN = reader.readString();
199 scope = SearchScope.valueOf(reader.readEnumerated());
200 derefPolicy = DereferencePolicy.valueOf(reader.readEnumerated());
201 sizeLimit = reader.readInteger();
202 timeLimit = reader.readInteger();
203 typesOnly = reader.readBoolean();
204 filter = Filter.readFrom(reader);
205
206 final ArrayList<String> attrs = new ArrayList<String>(5);
207 final ASN1StreamReaderSequence attrSequence = reader.beginSequence();
208 while (attrSequence.hasMoreElements())
209 {
210 attrs.add(reader.readString());
211 }
212
213 attributes = Collections.unmodifiableList(attrs);
214 }
215 catch (LDAPException le)
216 {
217 debugException(le);
218 throw le;
219 }
220 catch (Exception e)
221 {
222 debugException(e);
223
224 throw new LDAPException(ResultCode.DECODING_ERROR,
225 ERR_SEARCH_REQUEST_CANNOT_DECODE.get(getExceptionMessage(e)), e);
226 }
227 }
228
229
230
231 /**
232 * Retrieves the base DN for this search request.
233 *
234 * @return The base DN for this search request.
235 */
236 public String getBaseDN()
237 {
238 return baseDN;
239 }
240
241
242
243 /**
244 * Retrieves the scope for this search request.
245 *
246 * @return The scope for this search request.
247 */
248 public SearchScope getScope()
249 {
250 return scope;
251 }
252
253
254
255 /**
256 * Retrieves the policy to use for any aliases encountered during the search.
257 *
258 * @return The policy to use for any aliases encountered during the search.
259 */
260 public DereferencePolicy getDerefPolicy()
261 {
262 return derefPolicy;
263 }
264
265
266
267 /**
268 * Retrieves the maximum number of entries that the server should return for
269 * the search.
270 *
271 * @return The maximum number of entries that the server should return for
272 * the search, or zero if there is no limit.
273 */
274 public int getSizeLimit()
275 {
276 return sizeLimit;
277 }
278
279
280
281 /**
282 * Retrieves the maximum length of time in seconds the server should spend
283 * processing the search.
284 *
285 * @return The maximum length of time in seconds the server should spend
286 * processing the search, or zero if there is no limit.
287 */
288 public int getTimeLimit()
289 {
290 return timeLimit;
291 }
292
293
294
295 /**
296 * Indicates whether the server should return only attribute types or both
297 * attribute types and values.
298 *
299 * @return {@code true} if the server should return only attribute types, or
300 * {@code false} if both types and values should be returned.
301 */
302 public boolean typesOnly()
303 {
304 return typesOnly;
305 }
306
307
308
309 /**
310 * Retrieves the filter for this search request.
311 *
312 * @return The filter for this search request.
313 */
314 public Filter getFilter()
315 {
316 return filter;
317 }
318
319
320
321 /**
322 * Retrieves the set of requested attributes for this search request.
323 *
324 * @return The set of requested attributes for this search request.
325 */
326 public List<String> getAttributes()
327 {
328 return attributes;
329 }
330
331
332
333 /**
334 * {@inheritDoc}
335 */
336 public byte getProtocolOpType()
337 {
338 return LDAPMessage.PROTOCOL_OP_TYPE_SEARCH_REQUEST;
339 }
340
341
342
343 /**
344 * {@inheritDoc}
345 */
346 public ASN1Element encodeProtocolOp()
347 {
348 final ArrayList<ASN1Element> attrElements =
349 new ArrayList<ASN1Element>(attributes.size());
350 for (final String attribute : attributes)
351 {
352 attrElements.add(new ASN1OctetString(attribute));
353 }
354
355 return new ASN1Sequence(LDAPMessage.PROTOCOL_OP_TYPE_SEARCH_REQUEST,
356 new ASN1OctetString(baseDN),
357 new ASN1Enumerated(scope.intValue()),
358 new ASN1Enumerated(derefPolicy.intValue()),
359 new ASN1Integer(sizeLimit),
360 new ASN1Integer(timeLimit),
361 new ASN1Boolean(typesOnly),
362 filter.encode(),
363 new ASN1Sequence(attrElements));
364 }
365
366
367
368 /**
369 * Decodes the provided ASN.1 element as a search request protocol op.
370 *
371 * @param element The ASN.1 element to be decoded.
372 *
373 * @return The decoded search request protocol op.
374 *
375 * @throws LDAPException If the provided ASN.1 element cannot be decoded as
376 * a search request protocol op.
377 */
378 public static SearchRequestProtocolOp decodeProtocolOp(
379 final ASN1Element element)
380 throws LDAPException
381 {
382 try
383 {
384 final ASN1Element[] elements =
385 ASN1Sequence.decodeAsSequence(element).elements();
386 final String baseDN =
387 ASN1OctetString.decodeAsOctetString(elements[0]).stringValue();
388 final SearchScope scope = SearchScope.valueOf(
389 ASN1Enumerated.decodeAsEnumerated(elements[1]).intValue());
390 final DereferencePolicy derefPolicy = DereferencePolicy.valueOf(
391 ASN1Enumerated.decodeAsEnumerated(elements[2]).intValue());
392 final int sizeLimit = ASN1Integer.decodeAsInteger(elements[3]).intValue();
393 final int timeLimit = ASN1Integer.decodeAsInteger(elements[4]).intValue();
394 final boolean typesOnly =
395 ASN1Boolean.decodeAsBoolean(elements[5]).booleanValue();
396 final Filter filter = Filter.decode(elements[6]);
397
398 final ASN1Element[] attrElements =
399 ASN1Sequence.decodeAsSequence(elements[7]).elements();
400 final ArrayList<String> attributes =
401 new ArrayList<String>(attrElements.length);
402 for (final ASN1Element e : attrElements)
403 {
404 attributes.add(ASN1OctetString.decodeAsOctetString(e).stringValue());
405 }
406
407 return new SearchRequestProtocolOp(baseDN, scope, derefPolicy, sizeLimit,
408 timeLimit, typesOnly, filter, attributes);
409 }
410 catch (final Exception e)
411 {
412 debugException(e);
413 throw new LDAPException(ResultCode.DECODING_ERROR,
414 ERR_SEARCH_REQUEST_CANNOT_DECODE.get(getExceptionMessage(e)),
415 e);
416 }
417 }
418
419
420
421 /**
422 * {@inheritDoc}
423 */
424 public void writeTo(final ASN1Buffer buffer)
425 {
426 final ASN1BufferSequence opSequence =
427 buffer.beginSequence(LDAPMessage.PROTOCOL_OP_TYPE_SEARCH_REQUEST);
428 buffer.addOctetString(baseDN);
429 buffer.addEnumerated(scope.intValue());
430 buffer.addEnumerated(derefPolicy.intValue());
431 buffer.addInteger(sizeLimit);
432 buffer.addInteger(timeLimit);
433 buffer.addBoolean(typesOnly);
434 filter.writeTo(buffer);
435
436 final ASN1BufferSequence attrSequence = buffer.beginSequence();
437 for (final String s : attributes)
438 {
439 buffer.addOctetString(s);
440 }
441 attrSequence.end();
442 opSequence.end();
443 }
444
445
446
447 /**
448 * Creates a search request from this protocol op.
449 *
450 * @param controls The set of controls to include in the search request.
451 * It may be empty or {@code null} if no controls should be
452 * included.
453 *
454 * @return The search request that was created.
455 */
456 public SearchRequest toSearchRequest(final Control... controls)
457 {
458 final String[] attrArray = new String[attributes.size()];
459 attributes.toArray(attrArray);
460
461 return new SearchRequest(null, controls, baseDN, scope, derefPolicy,
462 sizeLimit, timeLimit, typesOnly, filter, attrArray);
463 }
464
465
466
467 /**
468 * Retrieves a string representation of this protocol op.
469 *
470 * @return A string representation of this protocol op.
471 */
472 @Override()
473 public String toString()
474 {
475 final StringBuilder buffer = new StringBuilder();
476 toString(buffer);
477 return buffer.toString();
478 }
479
480
481
482 /**
483 * {@inheritDoc}
484 */
485 public void toString(final StringBuilder buffer)
486 {
487 buffer.append("SearchRequestProtocolOp(baseDN='");
488 buffer.append(baseDN);
489 buffer.append("', scope='");
490 buffer.append(scope.toString());
491 buffer.append("', derefPolicy='");
492 buffer.append(derefPolicy.toString());
493 buffer.append("', sizeLimit=");
494 buffer.append(sizeLimit);
495 buffer.append(", timeLimit=");
496 buffer.append(timeLimit);
497 buffer.append(", typesOnly=");
498 buffer.append(typesOnly);
499 buffer.append(", filter='");
500 filter.toString(buffer);
501 buffer.append("', attributes={");
502
503 final Iterator<String> iterator = attributes.iterator();
504 while (iterator.hasNext())
505 {
506 buffer.append(iterator.next());
507 if (iterator.hasNext())
508 {
509 buffer.append(',');
510 }
511 }
512
513 buffer.append("})");
514 }
515 }