001    /*
002     * Copyright 2016 UnboundID Corp.
003     * All Rights Reserved.
004     */
005    /*
006     * Copyright (C) 2016 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.sdk.experimental;
022    
023    
024    
025    import java.util.Collections;
026    import java.util.List;
027    
028    import com.unboundid.ldap.sdk.DereferencePolicy;
029    import com.unboundid.ldap.sdk.Entry;
030    import com.unboundid.ldap.sdk.Filter;
031    import com.unboundid.ldap.sdk.LDAPException;
032    import com.unboundid.ldap.sdk.OperationType;
033    import com.unboundid.ldap.sdk.ResultCode;
034    import com.unboundid.ldap.sdk.SearchRequest;
035    import com.unboundid.ldap.sdk.SearchScope;
036    import com.unboundid.util.Debug;
037    import com.unboundid.util.NotMutable;
038    import com.unboundid.util.StaticUtils;
039    import com.unboundid.util.ThreadSafety;
040    import com.unboundid.util.ThreadSafetyLevel;
041    
042    import 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)
053    public 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    }