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