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