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
046 *   Nokia/Alcatel-Lucent 8661 server products.  These classes provide support
047 *   for proprietary functionality or for external specifications that are not
048 *   considered stable or mature enough to be guaranteed to work in an
049 *   interoperable way with 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.isEmpty())
197    {
198      referralURLs = Collections.emptyList();
199    }
200    else
201    {
202      final LinkedList<String> refs = new LinkedList<>();
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<>();
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.isEmpty())
239    {
240      serversAccessed = Collections.emptyList();
241    }
242    else
243    {
244      final LinkedList<String> servers = new LinkedList<>();
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.isEmpty())
258    {
259      usedPrivileges = Collections.emptyList();
260    }
261    else
262    {
263      final LinkedList<String> privileges = new LinkedList<>();
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.isEmpty())
277    {
278      preAuthZUsedPrivileges = Collections.emptyList();
279    }
280    else
281    {
282      final LinkedList<String> privileges = new LinkedList<>();
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.isEmpty())
294    {
295      missingPrivileges = Collections.emptyList();
296    }
297    else
298    {
299      final LinkedList<String> privileges = new LinkedList<>();
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.isEmpty())
312    {
313      indexesWithKeysAccessedNearEntryLimit = Collections.emptyList();
314    }
315    else
316    {
317      final LinkedList<String> indexes = new LinkedList<>();
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.isEmpty())
331    {
332      indexesWithKeysAccessedOverEntryLimit = Collections.emptyList();
333    }
334    else
335    {
336      final LinkedList<String> indexes = new LinkedList<>();
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  @Override()
357  public ResultCode getResultCode()
358  {
359    return resultCode;
360  }
361
362
363
364  /**
365   * Retrieves the diagnostic message for the operation.
366   *
367   * @return  The diagnostic message for the operation, or {@code null} if it is
368   *          not included in the log message.
369   */
370  @Override()
371  public String getDiagnosticMessage()
372  {
373    return diagnosticMessage;
374  }
375
376
377
378  /**
379   * Retrieves a message with additional information about the result of the
380   * operation.
381   *
382   * @return  A message with additional information about the result of the
383   *          operation, or {@code null} if it is not included in the log
384   *          message.
385   */
386  @Override()
387  public String getAdditionalInformation()
388  {
389    return additionalInformation;
390  }
391
392
393
394  /**
395   * Retrieves the matched DN for the operation.
396   *
397   * @return  The matched DN for the operation, or {@code null} if it is not
398   *          included in the log message.
399   */
400  @Override()
401  public String getMatchedDN()
402  {
403    return matchedDN;
404  }
405
406
407
408  /**
409   * Retrieves the list of referral URLs for the operation.
410   *
411   * @return  The list of referral URLs for the operation, or an empty list if
412   *          it is not included in the log message.
413   */
414  @Override()
415  public List<String> getReferralURLs()
416  {
417    return referralURLs;
418  }
419
420
421
422  /**
423   * Retrieves the number of intermediate response messages returned in the
424   * course of processing the operation.
425   *
426   * @return  The number of intermediate response messages returned to the
427   *          client in the course of processing the operation, or {@code null}
428   *          if it is not included in the log message.
429   */
430  @Override()
431  public Long getIntermediateResponsesReturned()
432  {
433    return intermediateResponsesReturned;
434  }
435
436
437
438  /**
439   * Retrieves the length of time in milliseconds required to process the
440   * operation.
441   *
442   * @return  The length of time in milliseconds required to process the
443   *          operation, or {@code null} if it is not included in the log
444   *          message.
445   */
446  @Override()
447  public Double getProcessingTimeMillis()
448  {
449    return processingTime;
450  }
451
452
453
454  /**
455   * Retrieves the length of time in milliseconds the operation was required to
456   * wait on the work queue.
457   *
458   * @return  The length of time in milliseconds the operation was required to
459   *          wait on the work queue, or {@code null} if it is not included in
460   *          the log message.
461   */
462  @Override()
463  public Double getQueueTimeMillis()
464  {
465    return queueTime;
466  }
467
468
469
470  /**
471   * Retrieves the OIDs of any response controls contained in the log message.
472   *
473   * @return  The OIDs of any response controls contained in the log message, or
474   *          an empty list if it is not included in the log message.
475   */
476  @Override()
477  public List<String> getResponseControlOIDs()
478  {
479    return responseControlOIDs;
480  }
481
482
483
484  /**
485   * Retrieves a list of the additional servers that were accessed in the course
486   * of processing the operation.  For example, if the access log message is
487   * from a Directory Proxy Server instance, then this may contain a list of the
488   * backend servers used to process the operation.
489   *
490   * @return  A list of the additional servers that were accessed in the course
491   *          of processing the operation, or an empty list if it is not
492   *          included in the log message.
493   */
494  @Override()
495  public List<String> getServersAccessed()
496  {
497    return serversAccessed;
498  }
499
500
501
502  /**
503   * Indicates whether the server accessed any uncached data in the course of
504   * processing the operation.
505   *
506   * @return  {@code true} if the server was known to access uncached data in
507   *          the course of processing the operation, {@code false} if the
508   *          server was known not to access uncached data, or {@code null} if
509   *          it is not included in the log message (and the server likely did
510   *          not access uncached data).
511   */
512  public Boolean getUncachedDataAccessed()
513  {
514    return uncachedDataAccessed;
515  }
516
517
518
519  /**
520   * Retrieves the content of the intermediate client result for the
521   * operation.
522   *
523   * @return  The content of the intermediate client result for the operation,
524   *          or {@code null} if it is not included in the log message.
525   */
526  @Override()
527  public String getIntermediateClientResult()
528  {
529    return intermediateClientResult;
530  }
531
532
533
534  /**
535   * Retrieves the number of entries returned to the client.
536   *
537   * @return  The number of entries returned to the client, or {@code null} if
538   *          it is not included in the log message.
539   */
540  public Long getEntriesReturned()
541  {
542    return entriesReturned;
543  }
544
545
546
547  /**
548   * Indicates whether the search was unindexed.
549   *
550   * @return  {@code Boolean.TRUE} if the search was unindexed,
551   *          {@code Boolean.FALSE} if it was not, or {@code null} if it is not
552   *          included in the log message.
553   */
554  public Boolean isUnindexed()
555  {
556    return isUnindexed;
557  }
558
559
560
561  /**
562   * Retrieves the alternate authorization DN for the operation.
563   *
564   * @return  The alternate authorization DN for the operation, or {@code null}
565   *          if it is not included in the log message.
566   */
567  public String getAlternateAuthorizationDN()
568  {
569    return authzDN;
570  }
571
572
573
574  /**
575   * Retrieves the address of the backend server to which the request has been
576   * forwarded.
577   *
578   * @return  The address of the backend server to which the request has been
579   *          forwarded, or {@code null} if it is not included in the log
580   *          message.
581   */
582  public String getTargetHost()
583  {
584    return targetHost;
585  }
586
587
588
589  /**
590   * Retrieves the port of the backend server to which the request has been
591   * forwarded.
592   *
593   * @return  The port of the backend server to which the request has been
594   *          forwarded, or {@code null} if it is not included in the log
595   *          message.
596   */
597  public Integer getTargetPort()
598  {
599    return targetPort;
600  }
601
602
603
604  /**
605   * Retrieves the protocol used to forward the request to the backend server.
606   *
607   * @return  The protocol used to forward the request to the backend server, or
608   *          {@code null} if it is not included in the log message.
609   */
610  public String getTargetProtocol()
611  {
612    return targetProtocol;
613  }
614
615
616
617  /**
618   * Retrieves the names of any privileges used during the course of processing
619   * the operation.
620   *
621   * @return  The names of any privileges used during the course of processing
622   *          the operation, or an empty list if no privileges were used or this
623   *          is not included in the log message.
624   */
625  public List<String> getUsedPrivileges()
626  {
627    return usedPrivileges;
628  }
629
630
631
632  /**
633   * Retrieves the names of any privileges used during the course of processing
634   * the operation before an alternate authorization identity was assigned.
635   *
636   * @return  The names of any privileges used during the course of processing
637   *          the operation before an alternate authorization identity was
638   *          assigned, or an empty list if no privileges were used or this is
639   *          not included in the log message.
640   */
641  public List<String> getPreAuthorizationUsedPrivileges()
642  {
643    return preAuthZUsedPrivileges;
644  }
645
646
647
648  /**
649   * Retrieves the names of any privileges that would have been required for
650   * processing the operation but that the requester did not have.
651   *
652   * @return  The names of any privileges that would have been required for
653   *          processing the operation but that the requester did not have, or
654   *          an empty list if there were no missing privileges or this is not
655   *          included in the log message.
656   */
657  public List<String> getMissingPrivileges()
658  {
659    return missingPrivileges;
660  }
661
662
663
664  /**
665   * Retrieves the names of any indexes for which one or more keys near
666   * (typically, within 80% of) the index entry limit were accessed while
667   * processing the operation.
668   *
669   * @return  The names of any indexes for which one or more keys near the index
670   *          entry limit were accessed while processing the operation, or an
671   *          empty list if no such index keys were accessed, or if this is not
672   *          included in the log message.
673   */
674  public List<String> getIndexesWithKeysAccessedNearEntryLimit()
675  {
676    return indexesWithKeysAccessedNearEntryLimit;
677  }
678
679
680
681  /**
682   * Retrieves the names of any indexes for which one or more keys over the
683   * index entry limit were accessed while processing the operation.
684   *
685   * @return  The names of any indexes for which one or more keys over the index
686   *          entry limit were accessed while processing the operation, or an
687   *          empty list if no such index keys were accessed, or if this is not
688   *          included in the log message.
689   */
690  public List<String> getIndexesWithKeysAccessedOverEntryLimit()
691  {
692    return indexesWithKeysAccessedOverEntryLimit;
693  }
694
695
696
697  /**
698   * {@inheritDoc}
699   */
700  @Override()
701  public AccessLogMessageType getMessageType()
702  {
703    return AccessLogMessageType.RESULT;
704  }
705}