001/*
002 * Copyright 2016-2017 UnboundID Corp.
003 * All Rights Reserved.
004 */
005/*
006 * Copyright (C) 2016-2017 UnboundID Corp.
007 *
008 * This program is free software; you can redistribute it and/or modify
009 * it under the terms of the GNU General Public License (GPLv2 only)
010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
011 * as published by the Free Software Foundation.
012 *
013 * This program is distributed in the hope that it will be useful,
014 * but WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
016 * GNU General Public License for more details.
017 *
018 * You should have received a copy of the GNU General Public License
019 * along with this program; if not, see <http://www.gnu.org/licenses>.
020 */
021package com.unboundid.ldap.sdk.experimental;
022
023
024
025import java.util.Collections;
026import java.util.List;
027
028import com.unboundid.ldap.sdk.DereferencePolicy;
029import com.unboundid.ldap.sdk.Entry;
030import com.unboundid.ldap.sdk.Filter;
031import com.unboundid.ldap.sdk.LDAPException;
032import com.unboundid.ldap.sdk.OperationType;
033import com.unboundid.ldap.sdk.ResultCode;
034import com.unboundid.ldap.sdk.SearchRequest;
035import com.unboundid.ldap.sdk.SearchScope;
036import com.unboundid.util.Debug;
037import com.unboundid.util.NotMutable;
038import com.unboundid.util.StaticUtils;
039import com.unboundid.util.ThreadSafety;
040import com.unboundid.util.ThreadSafetyLevel;
041
042import static com.unboundid.ldap.sdk.experimental.ExperimentalMessages.*;
043
044
045
046/**
047 * This class represents an entry that holds information about a search
048 * operation processed by an LDAP server, as per the specification described in
049 * draft-chu-ldap-logschema-00.
050 */
051@NotMutable()
052@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
053public final class DraftChuLDAPLogSchema00SearchEntry
054       extends DraftChuLDAPLogSchema00Entry
055{
056  /**
057   * The name of the attribute used to hold the alias dereference policy.
058   */
059  public static final String ATTR_DEREFERENCE_POLICY = "reqDerefAliases";
060
061
062
063  /**
064   * The name of the attribute used to hold the number of entries returned.
065   */
066  public static final String ATTR_ENTRIES_RETURNED = "reqEntries";
067
068
069
070  /**
071   * The name of the attribute used to hold the search filter.
072   */
073  public static final String ATTR_FILTER = "reqFilter";
074
075
076
077  /**
078   * The name of the attribute used to hold a requested attribute.
079   */
080  public static final String ATTR_REQUESTED_ATTRIBUTE = "reqAttr";
081
082
083
084  /**
085   * The name of the attribute used to hold the search scope.
086   */
087  public static final String ATTR_SCOPE = "reqScope";
088
089
090
091  /**
092   * The name of the attribute used to hold the requested size limit.
093   */
094  public static final String ATTR_SIZE_LIMIT = "reqSizeLimit";
095
096
097
098  /**
099   * The name of the attribute used to hold the requested time limit in seconds.
100   */
101  public static final String ATTR_TIME_LIMIT_SECONDS = "reqTimeLimit";
102
103
104
105  /**
106   * The name of the attribute used to hold the value of the typesOnly flag.
107   */
108  public static final String ATTR_TYPES_ONLY = "reqAttrsOnly";
109
110
111
112  /**
113   * The serial version UID for this serializable class.
114   */
115  private static final long serialVersionUID = 948178493925578134L;
116
117
118
119  // The types only flag.
120  private final boolean typesOnly;
121
122  // The alias dereference policy.
123  private final DereferencePolicy dereferencePolicy;
124
125  // The search filter.
126  private final Filter filter;
127
128  // The number of entries returned.
129  private final Integer entriesReturned;
130
131  // The requested size limit.
132  private final Integer requestedSizeLimit;
133
134  // The requested time limit in seconds.
135  private final Integer requestedTimeLimitSeconds;
136
137  // The list of requested attributes.
138  private final List<String> requestedAttributes;
139
140  // The search scope.
141  private final SearchScope scope;
142
143
144
145  /**
146   * Creates a new instance of this search access log entry from the provided
147   * entry.
148   *
149   * @param  entry  The entry used to create this search access log entry.
150   *
151   * @throws  LDAPException  If the provided entry cannot be decoded as a valid
152   *                         search access log entry as per the specification
153   *                         contained in draft-chu-ldap-logschema-00.
154   */
155  public DraftChuLDAPLogSchema00SearchEntry(final Entry entry)
156         throws LDAPException
157  {
158    super(entry, OperationType.SEARCH);
159
160
161    // Get the scope.
162    final String scopeStr = entry.getAttributeValue(ATTR_SCOPE);
163    if (scopeStr == null)
164    {
165      throw new LDAPException(ResultCode.DECODING_ERROR,
166           ERR_LOGSCHEMA_DECODE_MISSING_REQUIRED_ATTR.get(entry.getDN(),
167                ATTR_SCOPE));
168    }
169
170    final String lowerScope = StaticUtils.toLowerCase(scopeStr);
171    if (lowerScope.equals("base"))
172    {
173      scope = SearchScope.BASE;
174    }
175    else if (lowerScope.equals("one"))
176    {
177      scope = SearchScope.ONE;
178    }
179    else if (lowerScope.equals("sub"))
180    {
181      scope = SearchScope.SUB;
182    }
183    else if (lowerScope.equals("subord"))
184    {
185      scope = SearchScope.SUBORDINATE_SUBTREE;
186    }
187    else
188    {
189      throw new LDAPException(ResultCode.DECODING_ERROR,
190           ERR_LOGSCHEMA_DECODE_SEARCH_SCOPE_ERROR.get(entry.getDN(),
191                ATTR_SCOPE, scopeStr));
192    }
193
194
195    // Get the dereference policy.
196    final String derefStr = entry.getAttributeValue(ATTR_DEREFERENCE_POLICY);
197    if (derefStr == null)
198    {
199      throw new LDAPException(ResultCode.DECODING_ERROR,
200           ERR_LOGSCHEMA_DECODE_MISSING_REQUIRED_ATTR.get(entry.getDN(),
201                ATTR_DEREFERENCE_POLICY));
202    }
203
204    final String lowerDeref = StaticUtils.toLowerCase(derefStr);
205    if (lowerDeref.equals("never"))
206    {
207      dereferencePolicy = DereferencePolicy.NEVER;
208    }
209    else if (lowerDeref.equals("searching"))
210    {
211      dereferencePolicy = DereferencePolicy.SEARCHING;
212    }
213    else if (lowerDeref.equals("finding"))
214    {
215      dereferencePolicy = DereferencePolicy.FINDING;
216    }
217    else if (lowerDeref.equals("always"))
218    {
219      dereferencePolicy = DereferencePolicy.ALWAYS;
220    }
221    else
222    {
223      throw new LDAPException(ResultCode.DECODING_ERROR,
224           ERR_LOGSCHEMA_DECODE_SEARCH_DEREF_ERROR.get(entry.getDN(),
225                ATTR_DEREFERENCE_POLICY, derefStr));
226    }
227
228
229    // Get the typesOnly flag.
230    final String typesOnlyStr = entry.getAttributeValue(ATTR_TYPES_ONLY);
231    if (typesOnlyStr == null)
232    {
233      throw new LDAPException(ResultCode.DECODING_ERROR,
234           ERR_LOGSCHEMA_DECODE_MISSING_REQUIRED_ATTR.get(entry.getDN(),
235                ATTR_TYPES_ONLY));
236    }
237
238    final String lowerTypesOnly = StaticUtils.toLowerCase(typesOnlyStr);
239    if (lowerTypesOnly.equals("true"))
240    {
241      typesOnly = true;
242    }
243    else if (lowerTypesOnly.equals("false"))
244    {
245      typesOnly = false;
246    }
247    else
248    {
249      throw new LDAPException(ResultCode.DECODING_ERROR,
250           ERR_LOGSCHEMA_DECODE_SEARCH_TYPES_ONLY_ERROR.get(entry.getDN(),
251                ATTR_TYPES_ONLY, typesOnlyStr));
252    }
253
254
255    // Get the filter.  For some strange reason, this is allowed to be
256    // undefined.
257    final String filterStr = entry.getAttributeValue(ATTR_FILTER);
258    if (filterStr == null)
259    {
260      filter = null;
261    }
262    else
263    {
264      try
265      {
266        filter = Filter.create(filterStr);
267      }
268      catch (final Exception e)
269      {
270        Debug.debugException(e);
271        throw new LDAPException(ResultCode.DECODING_ERROR,
272             ERR_LOGSCHEMA_DECODE_SEARCH_FILTER_ERROR.get(entry.getDN(),
273                  ATTR_FILTER, filterStr),
274             e);
275      }
276    }
277
278
279    // Get the set of requested attributes.
280    final String[] requestedAttrArray =
281         entry.getAttributeValues(ATTR_REQUESTED_ATTRIBUTE);
282    if ((requestedAttrArray == null) || (requestedAttrArray.length == 0))
283    {
284      requestedAttributes = Collections.emptyList();
285    }
286    else
287    {
288      requestedAttributes =
289           Collections.unmodifiableList(StaticUtils.toList(requestedAttrArray));
290    }
291
292
293    // Get the requested size limit.
294    final String sizeLimitStr = entry.getAttributeValue(ATTR_SIZE_LIMIT);
295    if (sizeLimitStr == null)
296    {
297      requestedSizeLimit = null;
298    }
299    else
300    {
301      try
302      {
303        requestedSizeLimit = Integer.parseInt(sizeLimitStr);
304      }
305      catch (final Exception e)
306      {
307        Debug.debugException(e);
308        throw new LDAPException(ResultCode.DECODING_ERROR,
309             ERR_LOGSCHEMA_DECODE_SEARCH_INT_ERROR.get(entry.getDN(),
310                  ATTR_SIZE_LIMIT, sizeLimitStr),
311             e);
312      }
313    }
314
315
316    // Get the requested time limit.
317    final String timeLimitStr =
318         entry.getAttributeValue(ATTR_TIME_LIMIT_SECONDS);
319    if (timeLimitStr == null)
320    {
321      requestedTimeLimitSeconds = null;
322    }
323    else
324    {
325      try
326      {
327        requestedTimeLimitSeconds = Integer.parseInt(timeLimitStr);
328      }
329      catch (final Exception e)
330      {
331        Debug.debugException(e);
332        throw new LDAPException(ResultCode.DECODING_ERROR,
333             ERR_LOGSCHEMA_DECODE_SEARCH_INT_ERROR.get(entry.getDN(),
334                  ATTR_TIME_LIMIT_SECONDS, timeLimitStr),
335             e);
336      }
337    }
338
339
340    // Get the number of entries returned.
341    final String entriesReturnedStr =
342         entry.getAttributeValue(ATTR_ENTRIES_RETURNED);
343    if (entriesReturnedStr == null)
344    {
345      entriesReturned = null;
346    }
347    else
348    {
349      try
350      {
351        entriesReturned = Integer.parseInt(entriesReturnedStr);
352      }
353      catch (final Exception e)
354      {
355        Debug.debugException(e);
356        throw new LDAPException(ResultCode.DECODING_ERROR,
357             ERR_LOGSCHEMA_DECODE_SEARCH_INT_ERROR.get(entry.getDN(),
358                  ATTR_ENTRIES_RETURNED, entriesReturnedStr),
359             e);
360      }
361    }
362  }
363
364
365
366  /**
367   * Retrieves the scope for the search request described by this search access
368   * log entry.
369   *
370   * @return  The scope for the search request described by this search access
371   *          log entry.
372   */
373  public SearchScope getScope()
374  {
375    return scope;
376  }
377
378
379
380  /**
381   * Retrieves the alias dereference policy for the search request described by
382   * this search access log entry.
383   *
384   * @return  The alias dereference policy for the search request described by
385   *          this search access log entry.
386   */
387  public DereferencePolicy getDereferencePolicy()
388  {
389    return dereferencePolicy;
390  }
391
392
393
394  /**
395   * Retrieves the value of the typesOnly flag for the search request described
396   * by this search access log entry.
397   *
398   * @return  The value of the typesOnly flag for the search request described
399   *          by this search access log entry.
400   */
401  public boolean typesOnly()
402  {
403    return typesOnly;
404  }
405
406
407
408  /**
409   * Retrieves the filter for the search request described by this search access
410   * log entry, if available.
411   *
412   * @return  The filter for the search request described by this search access
413   *          log entry, or {@code null} if no filter was included in the access
414   *          log entry.
415   */
416  public Filter getFilter()
417  {
418    return filter;
419  }
420
421
422
423  /**
424   * Retrieves the requested size limit for the search request described by this
425   * search access log entry, if available.
426   *
427   * @return  The requested size limit for the search request described by this
428   *          search access log entry, or {@code null} if no size limit was
429   *          included in the access log entry.
430   */
431  public Integer getRequestedSizeLimit()
432  {
433    return requestedSizeLimit;
434  }
435
436
437
438  /**
439   * Retrieves the requested time limit (in seconds) for the search request
440   * described by this search access log entry, if available.
441   *
442   * @return  The requested time limit (in seconds) for the search request
443   *          described by this search access log entry, or {@code null} if no
444   *          time limit was included in the access log entry.
445   */
446  public Integer getRequestedTimeLimitSeconds()
447  {
448    return requestedTimeLimitSeconds;
449  }
450
451
452
453  /**
454   * Retrieves the requested attributes for the search request described by this
455   * search access log entry, if available.
456   *
457   * @return  The requested attributes for the search request described by this
458   *          search access log entry, or an empty list if no requested
459   *          attributes were included in the access log entry.
460   */
461  public List<String> getRequestedAttributes()
462  {
463    return requestedAttributes;
464  }
465
466
467
468  /**
469   * Retrieves the number of entries returned to the client in response to the
470   * search request described by this search access log entry, if available.
471   *
472   * @return  The number of entries returned to the client in response to the
473   *          search request described by this search access log entry, or
474   *          {@code null} if the number of entries returned was not included in
475   *          the access log entry.
476   */
477  public Integer getEntriesReturned()
478  {
479    return entriesReturned;
480  }
481
482
483
484  /**
485   * Retrieves a {@code SearchRequest} created from this search access log
486   * entry.  If the size limit or time limit was not present in the entry, a
487   * default of zero will be used.  If the filter was not present in the entry,
488   * a default of "(objectClass=*)" will be used.
489   *
490   * @return  The {@code SearchRequest} created from this search access log
491   *          entry.
492   */
493  public SearchRequest toSearchRequest()
494  {
495    final int sizeLimit =
496         ((requestedSizeLimit == null)
497              ? 0
498              : requestedSizeLimit);
499    final int timeLimit =
500         ((requestedTimeLimitSeconds == null)
501              ? 0
502              : requestedTimeLimitSeconds);
503    final Filter f =
504         ((filter == null)
505              ? Filter.createPresenceFilter("objectClass")
506              : filter);
507
508    final String[] attrArray =
509         requestedAttributes.toArray(StaticUtils.NO_STRINGS);
510
511    final SearchRequest searchRequest = new SearchRequest(getTargetEntryDN(),
512         scope, dereferencePolicy, sizeLimit, timeLimit, typesOnly, f,
513         attrArray);
514    searchRequest.setControls(getRequestControlArray());
515    return searchRequest;
516  }
517}