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 an extended 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 ExtendedResultAccessLogMessage
055       extends ExtendedRequestAccessLogMessage
056       implements OperationResultAccessLogMessage
057{
058  /**
059   * The serial version UID for this serializable class.
060   */
061  private static final long serialVersionUID = -3980496377400403461L;
062
063
064
065  // Indicates whether the any uncached data was accessed in the course of
066  // processing this operation.
067  private final Boolean uncachedDataAccessed;
068
069  // The processing time for the operation.
070  private final Double processingTime;
071
072  // The queue time for the operation.
073  private final Double queueTime;
074
075  // The list of privileges required for processing the operation that the
076  // requester did not have.
077  private final List<String> missingPrivileges;
078
079  // The list of privileges used during the course of processing the operation
080  // before an alternate authorization identity was assigned.
081  private final List<String> preAuthZUsedPrivileges;
082
083  // The list of referral URLs for the operation.
084  private final List<String> referralURLs;
085
086  // The list of response control OIDs for the operation.
087  private final List<String> responseControlOIDs;
088
089  // The list of servers accessed while processing the operation.
090  private final List<String> serversAccessed;
091
092  // The list of privileges used during the course of processing the operation.
093  private final List<String> usedPrivileges;
094
095  // The number of intermediate response messages returned to the client.
096  private final Long intermediateResponsesReturned;
097
098  // The result code for the operation.
099  private final ResultCode resultCode;
100
101  // Additional information about the operation result.
102  private final String additionalInformation;
103
104  // The name of the client connection policy selected for the client.
105  private final String clientConnectionPolicy;
106
107  // The diagnostic message for the operation.
108  private final String diagnosticMessage;
109
110  // The intermediate client result for the operation.
111  private final String intermediateClientResult;
112
113  // The matched DN for the operation.
114  private final String matchedDN;
115
116  // The OID of the extended response.
117  private final String responseOID;
118
119  // The port of the backend server to which the request has been forwarded.
120  private final Integer targetPort;
121
122  // The address of the backend server to which the request has been forwarded.
123  private final String targetHost;
124
125  // The protocol used to forward the request to the backend server.
126  private final String targetProtocol;
127
128
129
130  /**
131   * Creates a new extended result access log message from the provided message
132   * string.
133   *
134   * @param  s  The string to be parsed as an extended result access log
135   *            message.
136   *
137   * @throws  LogException  If the provided string cannot be parsed as a valid
138   *                        log message.
139   */
140  public ExtendedResultAccessLogMessage(final String s)
141         throws LogException
142  {
143    this(new LogMessage(s));
144  }
145
146
147
148  /**
149   * Creates a new extended result access log message from the provided log
150   * message.
151   *
152   * @param  m  The log message to be parsed as an extended result access log
153   *            message.
154   */
155  public ExtendedResultAccessLogMessage(final LogMessage m)
156  {
157    super(m);
158
159    diagnosticMessage        = getNamedValue("message");
160    additionalInformation    = getNamedValue("additionalInfo");
161    matchedDN                = getNamedValue("matchedDN");
162    processingTime           = getNamedValueAsDouble("etime");
163    queueTime                = getNamedValueAsDouble("qtime");
164    intermediateClientResult = getNamedValue("from");
165    responseOID              = getNamedValue("responseOID");
166    targetHost               = getNamedValue("targetHost");
167    targetPort               = getNamedValueAsInteger("targetPort");
168    targetProtocol           = getNamedValue("targetProtocol");
169    clientConnectionPolicy   = getNamedValue("clientConnectionPolicy");
170
171    intermediateResponsesReturned =
172         getNamedValueAsLong("intermediateResponsesReturned");
173
174    final Integer rcInteger = getNamedValueAsInteger("resultCode");
175    if (rcInteger == null)
176    {
177      resultCode = null;
178    }
179    else
180    {
181      resultCode = ResultCode.valueOf(rcInteger);
182    }
183
184    final String refStr = getNamedValue("referralURLs");
185    if ((refStr == null) || (refStr.length() == 0))
186    {
187      referralURLs = Collections.emptyList();
188    }
189    else
190    {
191      final LinkedList<String> refs = new LinkedList<String>();
192      int startPos = 0;
193      while (true)
194      {
195        final int commaPos = refStr.indexOf(",ldap", startPos);
196        if (commaPos < 0)
197        {
198          refs.add(refStr.substring(startPos));
199          break;
200        }
201        else
202        {
203          refs.add(refStr.substring(startPos, commaPos));
204          startPos = commaPos+1;
205        }
206      }
207      referralURLs = Collections.unmodifiableList(refs);
208    }
209
210    final String controlStr = getNamedValue("responseControls");
211    if (controlStr == null)
212    {
213      responseControlOIDs = Collections.emptyList();
214    }
215    else
216    {
217      final LinkedList<String> controlList = new LinkedList<String>();
218      final StringTokenizer t = new StringTokenizer(controlStr, ",");
219      while (t.hasMoreTokens())
220      {
221        controlList.add(t.nextToken());
222      }
223      responseControlOIDs = Collections.unmodifiableList(controlList);
224    }
225
226    final String serversAccessedStr = getNamedValue("serversAccessed");
227    if ((serversAccessedStr == null) || (serversAccessedStr.length() == 0))
228    {
229      serversAccessed = Collections.emptyList();
230    }
231    else
232    {
233      final LinkedList<String> servers = new LinkedList<String>();
234      final StringTokenizer tokenizer =
235           new StringTokenizer(serversAccessedStr, ",");
236      while (tokenizer.hasMoreTokens())
237      {
238        servers.add(tokenizer.nextToken());
239      }
240      serversAccessed = Collections.unmodifiableList(servers);
241    }
242
243    uncachedDataAccessed = getNamedValueAsBoolean("uncachedDataAccessed");
244
245    final String usedPrivilegesStr = getNamedValue("usedPrivileges");
246    if ((usedPrivilegesStr == null) || (usedPrivilegesStr.length() == 0))
247    {
248      usedPrivileges = Collections.emptyList();
249    }
250    else
251    {
252      final LinkedList<String> privileges = new LinkedList<String>();
253      final StringTokenizer tokenizer =
254           new StringTokenizer(usedPrivilegesStr, ",");
255      while (tokenizer.hasMoreTokens())
256      {
257        privileges.add(tokenizer.nextToken());
258      }
259      usedPrivileges = Collections.unmodifiableList(privileges);
260    }
261
262    final String preAuthZUsedPrivilegesStr =
263         getNamedValue("preAuthZUsedPrivileges");
264    if ((preAuthZUsedPrivilegesStr == null) ||
265        (preAuthZUsedPrivilegesStr.length() == 0))
266    {
267      preAuthZUsedPrivileges = Collections.emptyList();
268    }
269    else
270    {
271      final LinkedList<String> privileges = new LinkedList<String>();
272      final StringTokenizer tokenizer =
273           new StringTokenizer(preAuthZUsedPrivilegesStr, ",");
274      while (tokenizer.hasMoreTokens())
275      {
276        privileges.add(tokenizer.nextToken());
277      }
278      preAuthZUsedPrivileges = Collections.unmodifiableList(privileges);
279    }
280
281    final String missingPrivilegesStr = getNamedValue("missingPrivileges");
282    if ((missingPrivilegesStr == null) || (missingPrivilegesStr.length() == 0))
283    {
284      missingPrivileges = Collections.emptyList();
285    }
286    else
287    {
288      final LinkedList<String> privileges = new LinkedList<String>();
289      final StringTokenizer tokenizer =
290           new StringTokenizer(missingPrivilegesStr, ",");
291      while (tokenizer.hasMoreTokens())
292      {
293        privileges.add(tokenizer.nextToken());
294      }
295      missingPrivileges = Collections.unmodifiableList(privileges);
296    }
297  }
298
299
300
301  /**
302   * Retrieves the result code for the operation.
303   *
304   * @return  The result code for the operation, or {@code null} if it is not
305   *          included in the log message.
306   */
307  public ResultCode getResultCode()
308  {
309    return resultCode;
310  }
311
312
313
314  /**
315   * Retrieves the diagnostic message for the operation.
316   *
317   * @return  The diagnostic message for the operation, or {@code null} if it is
318   *          not included in the log message.
319   */
320  public String getDiagnosticMessage()
321  {
322    return diagnosticMessage;
323  }
324
325
326
327  /**
328   * Retrieves a message with additional information about the result of the
329   * operation.
330   *
331   * @return  A message with additional information about the result of the
332   *          operation, or {@code null} if it is not included in the log
333   *          message.
334   */
335  public String getAdditionalInformation()
336  {
337    return additionalInformation;
338  }
339
340
341
342  /**
343   * Retrieves the matched DN for the operation.
344   *
345   * @return  The matched DN for the operation, or {@code null} if it is not
346   *          included in the log message.
347   */
348  public String getMatchedDN()
349  {
350    return matchedDN;
351  }
352
353
354
355  /**
356   * Retrieves the list of referral URLs for the operation.
357   *
358   * @return  The list of referral URLs for the operation, or an empty list if
359   *          it is not included in the log message.
360   */
361  public List<String> getReferralURLs()
362  {
363    return referralURLs;
364  }
365
366
367
368  /**
369   * Retrieves a list of the additional servers that were accessed in the course
370   * of processing the operation.  For example, if the access log message is
371   * from a Directory Proxy Server instance, then this may contain a list of the
372   * backend servers used to process the operation.
373   *
374   * @return  A list of the additional servers that were accessed in the course
375   *          of processing the operation, or an empty list if it is not
376   *          included in the log message.
377   */
378  public List<String> getServersAccessed()
379  {
380    return serversAccessed;
381  }
382
383
384
385  /**
386   * Indicates whether the server accessed any uncached data in the course of
387   * processing the operation.
388   *
389   * @return  {@code true} if the server was known to access uncached data in
390   *          the course of processing the operation, {@code false} if the
391   *          server was known not to access uncached data, or {@code null} if
392   *          it is not included in the log message (and the server likely did
393   *          not access uncached data).
394   */
395  public Boolean getUncachedDataAccessed()
396  {
397    return uncachedDataAccessed;
398  }
399
400
401
402  /**
403   * Retrieves the number of intermediate response messages returned in the
404   * course of processing the operation.
405   *
406   * @return  The number of intermediate response messages returned to the
407   *          client in the course of processing the operation, or {@code null}
408   *          if it is not included in the log message.
409   */
410  public Long getIntermediateResponsesReturned()
411  {
412    return intermediateResponsesReturned;
413  }
414
415
416
417  /**
418   * Retrieves the length of time in milliseconds required to process the
419   * operation.
420   *
421   * @return  The length of time in milliseconds required to process the
422   *          operation, or {@code null} if it is not included in the log
423   *          message.
424   */
425  public Double getProcessingTimeMillis()
426  {
427    return processingTime;
428  }
429
430
431
432  /**
433   * Retrieves the length of time in milliseconds the operation was required to
434   * wait on the work queue.
435   *
436   * @return  The length of time in milliseconds the operation was required to
437   *          wait on the work queue, or {@code null} if it is not included in
438   *          the log message.
439   */
440  public Double getQueueTimeMillis()
441  {
442    return queueTime;
443  }
444
445
446
447  /**
448   * Retrieves the OIDs of any response controls contained in the log message.
449   *
450   * @return  The OIDs of any response controls contained in the log message, or
451   *          an empty list if it is not included in the log message.
452   */
453  public List<String> getResponseControlOIDs()
454  {
455    return responseControlOIDs;
456  }
457
458
459
460  /**
461   * Retrieves the content of the intermediate client result for the
462   * operation.
463   *
464   * @return  The content of the intermediate client result for the operation,
465   *          or {@code null} if it is not included in the log message.
466   */
467  public String getIntermediateClientResult()
468  {
469    return intermediateClientResult;
470  }
471
472
473
474  /**
475   * Retrieves the OID for the extended response.
476   *
477   * @return  The OID for the extended response, or {@code null} if it is not
478   *          included in the log message.
479   */
480  public String getResponseOID()
481  {
482    return responseOID;
483  }
484
485
486
487  /**
488   * Retrieves the address of the backend server to which the request has been
489   * forwarded.
490   *
491   * @return  The address of the backend server to which the request has been
492   *          forwarded, or {@code null} if it is not included in the log
493   *          message.
494   */
495  public String getTargetHost()
496  {
497    return targetHost;
498  }
499
500
501
502  /**
503   * Retrieves the port of the backend server to which the request has been
504   * forwarded.
505   *
506   * @return  The port of the backend server to which the request has been
507   *          forwarded, or {@code null} if it is not included in the log
508   *          message.
509   */
510  public Integer getTargetPort()
511  {
512    return targetPort;
513  }
514
515
516
517  /**
518   * Retrieves the protocol used to forward the request to the backend server.
519   *
520   * @return  The protocol used to forward the request to the backend server, or
521   *          {@code null} if it is not included in the log message.
522   */
523  public String getTargetProtocol()
524  {
525    return targetProtocol;
526  }
527
528
529
530  /**
531   * Retrieves the name of the client connection policy that was selected for
532   * the client connection.
533   *
534   * @return  The name of the client connection policy that was selected for the
535   *          client connection, or {@code null} if it is not included in the
536   *          log message.
537   */
538  public String getClientConnectionPolicy()
539  {
540    return clientConnectionPolicy;
541  }
542
543
544
545  /**
546   * Retrieves the names of any privileges used during the course of processing
547   * the operation.
548   *
549   * @return  The names of any privileges used during the course of processing
550   *          the operation, or an empty list if no privileges were used or this
551   *          is not included in the log message.
552   */
553  public List<String> getUsedPrivileges()
554  {
555    return usedPrivileges;
556  }
557
558
559
560  /**
561   * Retrieves the names of any privileges used during the course of processing
562   * the operation before an alternate authorization identity was assigned.
563   *
564   * @return  The names of any privileges used during the course of processing
565   *          the operation before an alternate authorization identity was
566   *          assigned, or an empty list if no privileges were used or this is
567   *          not included in the log message.
568   */
569  public List<String> getPreAuthorizationUsedPrivileges()
570  {
571    return preAuthZUsedPrivileges;
572  }
573
574
575
576  /**
577   * Retrieves the names of any privileges that would have been required for
578   * processing the operation but that the requester did not have.
579   *
580   * @return  The names of any privileges that would have been required for
581   *          processing the operation but that the requester did not have, or
582   *          an empty list if there were no missing privileges or this is not
583   *          included in the log message.
584   */
585  public List<String> getMissingPrivileges()
586  {
587    return missingPrivileges;
588  }
589
590
591
592  /**
593   * {@inheritDoc}
594   */
595  @Override()
596  public AccessLogMessageType getMessageType()
597  {
598    return AccessLogMessageType.RESULT;
599  }
600}