001/*
002 * Copyright 2009-2018 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright (C) 2015-2018 Ping Identity Corporation
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.unboundidds.logs;
022
023
024
025import java.util.Collections;
026import java.util.LinkedList;
027import java.util.List;
028import java.util.StringTokenizer;
029
030import com.unboundid.ldap.sdk.ResultCode;
031import com.unboundid.util.NotMutable;
032import com.unboundid.util.ThreadSafety;
033import com.unboundid.util.ThreadSafetyLevel;
034
035
036
037/**
038 * This class provides a data structure that holds information about a log
039 * message that may appear in the Directory Server access log about the result
040 * of a search operation processed by the Directory Server.
041 * <BR>
042 * <BLOCKQUOTE>
043 *   <B>NOTE:</B>  This class, and other classes within the
044 *   {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only
045 *   supported for use against Ping Identity, UnboundID, and Alcatel-Lucent 8661
046 *   server products.  These classes provide support for proprietary
047 *   functionality or for external specifications that are not considered stable
048 *   or mature enough to be guaranteed to work in an interoperable way with
049 *   other types of LDAP servers.
050 * </BLOCKQUOTE>
051 */
052@NotMutable()
053@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
054public final class SearchResultAccessLogMessage
055       extends SearchRequestAccessLogMessage
056       implements OperationResultAccessLogMessage
057{
058  /**
059   * The serial version UID for this serializable class.
060   */
061  private static final long serialVersionUID = 7181644154168110011L;
062
063
064
065  // Indicates whether the search was unindexed.
066  private final Boolean isUnindexed;
067
068  // Indicates whether the any uncached data was accessed in the course of
069  // processing this operation.
070  private final Boolean uncachedDataAccessed;
071
072  // The processing time for the operation.
073  private final Double processingTime;
074
075  // The queue time for the operation.
076  private final Double queueTime;
077
078  // The list of indexes for which keys near the index entry limit were accessed
079  // while processing the operation.
080  private final List<String> indexesWithKeysAccessedNearEntryLimit;
081
082  // The list of indexes for which keys over the index entry limit were accessed
083  // while processing the operation.
084  private final List<String> indexesWithKeysAccessedOverEntryLimit;
085
086  // The list of privileges required for processing the operation that the
087  // requester did not have.
088  private final List<String> missingPrivileges;
089
090  // The list of privileges used during the course of processing the operation
091  // before an alternate authorization identity was assigned.
092  private final List<String> preAuthZUsedPrivileges;
093
094  // The list of referral URLs for the operation.
095  private final List<String> referralURLs;
096
097  // The list of response control OIDs for the operation.
098  private final List<String> responseControlOIDs;
099
100  // The list of servers accessed while processing the operation.
101  private final List<String> serversAccessed;
102
103  // The list of privileges used during the course of processing the operation.
104  private final List<String> usedPrivileges;
105
106  // The number of entries returned to the client.
107  private final Long entriesReturned;
108
109  // The number of intermediate response messages returned to the client.
110  private final Long intermediateResponsesReturned;
111
112  // The result code for the operation.
113  private final ResultCode resultCode;
114
115  // Additional information about the operation result.
116  private final String additionalInformation;
117
118  // The alternate authorization DN for the operation.
119  private final String authzDN;
120
121  // The diagnostic message for the operation.
122  private final String diagnosticMessage;
123
124  // The intermediate client result for the operation.
125  private final String intermediateClientResult;
126
127  // The matched DN for the operation.
128  private final String matchedDN;
129
130  // The port of the backend server to which the request has been forwarded.
131  private final Integer targetPort;
132
133  // The address of the backend server to which the request has been forwarded.
134  private final String targetHost;
135
136  // The protocol used to forward the request to the backend server.
137  private final String targetProtocol;
138
139
140
141  /**
142   * Creates a new search result access log message from the provided message
143   * string.
144   *
145   * @param  s  The string to be parsed as a search result access log message.
146   *
147   * @throws  LogException  If the provided string cannot be parsed as a valid
148   *                        log message.
149   */
150  public SearchResultAccessLogMessage(final String s)
151         throws LogException
152  {
153    this(new LogMessage(s));
154  }
155
156
157
158  /**
159   * Creates a new search result access log message from the provided log
160   * message.
161   *
162   * @param  m  The log message to be parsed as a search result access log
163   *            message.
164   */
165  public SearchResultAccessLogMessage(final LogMessage m)
166  {
167    super(m);
168
169    diagnosticMessage = getNamedValue("message");
170    additionalInformation = getNamedValue("additionalInfo");
171    matchedDN = getNamedValue("matchedDN");
172    processingTime = getNamedValueAsDouble("etime");
173    queueTime = getNamedValueAsDouble("qtime");
174    intermediateClientResult = getNamedValue("from");
175    entriesReturned = getNamedValueAsLong("entriesReturned");
176    isUnindexed = getNamedValueAsBoolean("unindexed");
177    authzDN = getNamedValue("authzDN");
178    targetHost = getNamedValue("targetHost");
179    targetPort = getNamedValueAsInteger("targetPort");
180    targetProtocol = getNamedValue("targetProtocol");
181
182    intermediateResponsesReturned =
183         getNamedValueAsLong("intermediateResponsesReturned");
184
185    final Integer rcInteger = getNamedValueAsInteger("resultCode");
186    if (rcInteger == null)
187    {
188      resultCode = null;
189    }
190    else
191    {
192      resultCode = ResultCode.valueOf(rcInteger);
193    }
194
195    final String refStr = getNamedValue("referralURLs");
196    if ((refStr == null) || (refStr.length() == 0))
197    {
198      referralURLs = Collections.emptyList();
199    }
200    else
201    {
202      final LinkedList<String> refs = new LinkedList<String>();
203      int startPos = 0;
204      while (true)
205      {
206        final int commaPos = refStr.indexOf(",ldap", startPos);
207        if (commaPos < 0)
208        {
209          refs.add(refStr.substring(startPos));
210          break;
211        }
212        else
213        {
214          refs.add(refStr.substring(startPos, commaPos));
215          startPos = commaPos + 1;
216        }
217      }
218      referralURLs = Collections.unmodifiableList(refs);
219    }
220
221    final String controlStr = getNamedValue("responseControls");
222    if (controlStr == null)
223    {
224      responseControlOIDs = Collections.emptyList();
225    }
226    else
227    {
228      final LinkedList<String> controlList = new LinkedList<String>();
229      final StringTokenizer t = new StringTokenizer(controlStr, ",");
230      while (t.hasMoreTokens())
231      {
232        controlList.add(t.nextToken());
233      }
234      responseControlOIDs = Collections.unmodifiableList(controlList);
235    }
236
237    final String serversAccessedStr = getNamedValue("serversAccessed");
238    if ((serversAccessedStr == null) || (serversAccessedStr.length() == 0))
239    {
240      serversAccessed = Collections.emptyList();
241    }
242    else
243    {
244      final LinkedList<String> servers = new LinkedList<String>();
245      final StringTokenizer tokenizer =
246           new StringTokenizer(serversAccessedStr, ",");
247      while (tokenizer.hasMoreTokens())
248      {
249        servers.add(tokenizer.nextToken());
250      }
251      serversAccessed = Collections.unmodifiableList(servers);
252    }
253
254    uncachedDataAccessed = getNamedValueAsBoolean("uncachedDataAccessed");
255
256    final String usedPrivilegesStr = getNamedValue("usedPrivileges");
257    if ((usedPrivilegesStr == null) || (usedPrivilegesStr.length() == 0))
258    {
259      usedPrivileges = Collections.emptyList();
260    }
261    else
262    {
263      final LinkedList<String> privileges = new LinkedList<String>();
264      final StringTokenizer tokenizer =
265           new StringTokenizer(usedPrivilegesStr, ",");
266      while (tokenizer.hasMoreTokens())
267      {
268        privileges.add(tokenizer.nextToken());
269      }
270      usedPrivileges = Collections.unmodifiableList(privileges);
271    }
272
273    final String preAuthZUsedPrivilegesStr =
274         getNamedValue("preAuthZUsedPrivileges");
275    if ((preAuthZUsedPrivilegesStr == null) ||
276         (preAuthZUsedPrivilegesStr.length() == 0))
277    {
278      preAuthZUsedPrivileges = Collections.emptyList();
279    }
280    else
281    {
282      final LinkedList<String> privileges = new LinkedList<String>();
283      final StringTokenizer tokenizer =
284           new StringTokenizer(preAuthZUsedPrivilegesStr, ",");
285      while (tokenizer.hasMoreTokens())
286      {
287        privileges.add(tokenizer.nextToken());
288      }
289      preAuthZUsedPrivileges = Collections.unmodifiableList(privileges);
290    }
291
292    final String missingPrivilegesStr = getNamedValue("missingPrivileges");
293    if ((missingPrivilegesStr == null) || (missingPrivilegesStr.length() == 0))
294    {
295      missingPrivileges = Collections.emptyList();
296    }
297    else
298    {
299      final LinkedList<String> privileges = new LinkedList<String>();
300      final StringTokenizer tokenizer =
301           new StringTokenizer(missingPrivilegesStr, ",");
302      while (tokenizer.hasMoreTokens())
303      {
304        privileges.add(tokenizer.nextToken());
305      }
306      missingPrivileges = Collections.unmodifiableList(privileges);
307    }
308
309    final String indexesNearLimitStr =
310         getNamedValue("indexesWithKeysAccessedNearEntryLimit");
311    if ((indexesNearLimitStr == null) || (indexesNearLimitStr.length() == 0))
312    {
313      indexesWithKeysAccessedNearEntryLimit = Collections.emptyList();
314    }
315    else
316    {
317      final LinkedList<String> indexes = new LinkedList<String>();
318      final StringTokenizer tokenizer =
319           new StringTokenizer(indexesNearLimitStr, ",");
320      while (tokenizer.hasMoreTokens())
321      {
322        indexes.add(tokenizer.nextToken());
323      }
324      indexesWithKeysAccessedNearEntryLimit =
325           Collections.unmodifiableList(indexes);
326    }
327
328    final String indexesOverLimitStr =
329         getNamedValue("indexesWithKeysAccessedExceedingEntryLimit");
330    if ((indexesOverLimitStr == null) || (indexesOverLimitStr.length() == 0))
331    {
332      indexesWithKeysAccessedOverEntryLimit = Collections.emptyList();
333    }
334    else
335    {
336      final LinkedList<String> indexes = new LinkedList<String>();
337      final StringTokenizer tokenizer =
338           new StringTokenizer(indexesOverLimitStr, ",");
339      while (tokenizer.hasMoreTokens())
340      {
341        indexes.add(tokenizer.nextToken());
342      }
343      indexesWithKeysAccessedOverEntryLimit =
344           Collections.unmodifiableList(indexes);
345    }
346  }
347
348
349
350  /**
351   * Retrieves the result code for the operation.
352   *
353   * @return  The result code for the operation, or {@code null} if it is not
354   *          included in the log message.
355   */
356  public ResultCode getResultCode()
357  {
358    return resultCode;
359  }
360
361
362
363  /**
364   * Retrieves the diagnostic message for the operation.
365   *
366   * @return  The diagnostic message for the operation, or {@code null} if it is
367   *          not included in the log message.
368   */
369  public String getDiagnosticMessage()
370  {
371    return diagnosticMessage;
372  }
373
374
375
376  /**
377   * Retrieves a message with additional information about the result of the
378   * operation.
379   *
380   * @return  A message with additional information about the result of the
381   *          operation, or {@code null} if it is not included in the log
382   *          message.
383   */
384  public String getAdditionalInformation()
385  {
386    return additionalInformation;
387  }
388
389
390
391  /**
392   * Retrieves the matched DN for the operation.
393   *
394   * @return  The matched DN for the operation, or {@code null} if it is not
395   *          included in the log message.
396   */
397  public String getMatchedDN()
398  {
399    return matchedDN;
400  }
401
402
403
404  /**
405   * Retrieves the list of referral URLs for the operation.
406   *
407   * @return  The list of referral URLs for the operation, or an empty list if
408   *          it is not included in the log message.
409   */
410  public List<String> getReferralURLs()
411  {
412    return referralURLs;
413  }
414
415
416
417  /**
418   * Retrieves the number of intermediate response messages returned in the
419   * course of processing the operation.
420   *
421   * @return  The number of intermediate response messages returned to the
422   *          client in the course of processing the operation, or {@code null}
423   *          if it is not included in the log message.
424   */
425  public Long getIntermediateResponsesReturned()
426  {
427    return intermediateResponsesReturned;
428  }
429
430
431
432  /**
433   * Retrieves the length of time in milliseconds required to process the
434   * operation.
435   *
436   * @return  The length of time in milliseconds required to process the
437   *          operation, or {@code null} if it is not included in the log
438   *          message.
439   */
440  public Double getProcessingTimeMillis()
441  {
442    return processingTime;
443  }
444
445
446
447  /**
448   * Retrieves the length of time in milliseconds the operation was required to
449   * wait on the work queue.
450   *
451   * @return  The length of time in milliseconds the operation was required to
452   *          wait on the work queue, or {@code null} if it is not included in
453   *          the log message.
454   */
455  public Double getQueueTimeMillis()
456  {
457    return queueTime;
458  }
459
460
461
462  /**
463   * Retrieves the OIDs of any response controls contained in the log message.
464   *
465   * @return  The OIDs of any response controls contained in the log message, or
466   *          an empty list if it is not included in the log message.
467   */
468  public List<String> getResponseControlOIDs()
469  {
470    return responseControlOIDs;
471  }
472
473
474
475  /**
476   * Retrieves a list of the additional servers that were accessed in the course
477   * of processing the operation.  For example, if the access log message is
478   * from a Directory Proxy Server instance, then this may contain a list of the
479   * backend servers used to process the operation.
480   *
481   * @return  A list of the additional servers that were accessed in the course
482   *          of processing the operation, or an empty list if it is not
483   *          included in the log message.
484   */
485  public List<String> getServersAccessed()
486  {
487    return serversAccessed;
488  }
489
490
491
492  /**
493   * Indicates whether the server accessed any uncached data in the course of
494   * processing the operation.
495   *
496   * @return  {@code true} if the server was known to access uncached data in
497   *          the course of processing the operation, {@code false} if the
498   *          server was known not to access uncached data, or {@code null} if
499   *          it is not included in the log message (and the server likely did
500   *          not access uncached data).
501   */
502  public Boolean getUncachedDataAccessed()
503  {
504    return uncachedDataAccessed;
505  }
506
507
508
509  /**
510   * Retrieves the content of the intermediate client result for the
511   * operation.
512   *
513   * @return  The content of the intermediate client result for the operation,
514   *          or {@code null} if it is not included in the log message.
515   */
516  public String getIntermediateClientResult()
517  {
518    return intermediateClientResult;
519  }
520
521
522
523  /**
524   * Retrieves the number of entries returned to the client.
525   *
526   * @return  The number of entries returned to the client, or {@code null} if
527   *          it is not included in the log message.
528   */
529  public Long getEntriesReturned()
530  {
531    return entriesReturned;
532  }
533
534
535
536  /**
537   * Indicates whether the search was unindexed.
538   *
539   * @return  {@code Boolean.TRUE} if the search was unindexed,
540   *          {@code Boolean.FALSE} if it was not, or {@code null} if it is not
541   *          included in the log message.
542   */
543  public Boolean isUnindexed()
544  {
545    return isUnindexed;
546  }
547
548
549
550  /**
551   * Retrieves the alternate authorization DN for the operation.
552   *
553   * @return  The alternate authorization DN for the operation, or {@code null}
554   *          if it is not included in the log message.
555   */
556  public String getAlternateAuthorizationDN()
557  {
558    return authzDN;
559  }
560
561
562
563  /**
564   * Retrieves the address of the backend server to which the request has been
565   * forwarded.
566   *
567   * @return  The address of the backend server to which the request has been
568   *          forwarded, or {@code null} if it is not included in the log
569   *          message.
570   */
571  public String getTargetHost()
572  {
573    return targetHost;
574  }
575
576
577
578  /**
579   * Retrieves the port of the backend server to which the request has been
580   * forwarded.
581   *
582   * @return  The port of the backend server to which the request has been
583   *          forwarded, or {@code null} if it is not included in the log
584   *          message.
585   */
586  public Integer getTargetPort()
587  {
588    return targetPort;
589  }
590
591
592
593  /**
594   * Retrieves the protocol used to forward the request to the backend server.
595   *
596   * @return  The protocol used to forward the request to the backend server, or
597   *          {@code null} if it is not included in the log message.
598   */
599  public String getTargetProtocol()
600  {
601    return targetProtocol;
602  }
603
604
605
606  /**
607   * Retrieves the names of any privileges used during the course of processing
608   * the operation.
609   *
610   * @return  The names of any privileges used during the course of processing
611   *          the operation, or an empty list if no privileges were used or this
612   *          is not included in the log message.
613   */
614  public List<String> getUsedPrivileges()
615  {
616    return usedPrivileges;
617  }
618
619
620
621  /**
622   * Retrieves the names of any privileges used during the course of processing
623   * the operation before an alternate authorization identity was assigned.
624   *
625   * @return  The names of any privileges used during the course of processing
626   *          the operation before an alternate authorization identity was
627   *          assigned, or an empty list if no privileges were used or this is
628   *          not included in the log message.
629   */
630  public List<String> getPreAuthorizationUsedPrivileges()
631  {
632    return preAuthZUsedPrivileges;
633  }
634
635
636
637  /**
638   * Retrieves the names of any privileges that would have been required for
639   * processing the operation but that the requester did not have.
640   *
641   * @return  The names of any privileges that would have been required for
642   *          processing the operation but that the requester did not have, or
643   *          an empty list if there were no missing privileges or this is not
644   *          included in the log message.
645   */
646  public List<String> getMissingPrivileges()
647  {
648    return missingPrivileges;
649  }
650
651
652
653  /**
654   * Retrieves the names of any indexes for which one or more keys near
655   * (typically, within 80% of) the index entry limit were accessed while
656   * processing the operation.
657   *
658   * @return  The names of any indexes for which one or more keys near the index
659   *          entry limit were accessed while processing the operation, or an
660   *          empty list if no such index keys were accessed, or if this is not
661   *          included in the log message.
662   */
663  public List<String> getIndexesWithKeysAccessedNearEntryLimit()
664  {
665    return indexesWithKeysAccessedNearEntryLimit;
666  }
667
668
669
670  /**
671   * Retrieves the names of any indexes for which one or more keys over the
672   * index entry limit were accessed while processing the operation.
673   *
674   * @return  The names of any indexes for which one or more keys over the index
675   *          entry limit were accessed while processing the operation, or an
676   *          empty list if no such index keys were accessed, or if this is not
677   *          included in the log message.
678   */
679  public List<String> getIndexesWithKeysAccessedOverEntryLimit()
680  {
681    return indexesWithKeysAccessedOverEntryLimit;
682  }
683
684
685
686  /**
687   * {@inheritDoc}
688   */
689  @Override()
690  public AccessLogMessageType getMessageType()
691  {
692    return AccessLogMessageType.RESULT;
693  }
694}