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
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 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.isEmpty())
186    {
187      referralURLs = Collections.emptyList();
188    }
189    else
190    {
191      final LinkedList<String> refs = new LinkedList<>();
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<>();
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.isEmpty())
228    {
229      serversAccessed = Collections.emptyList();
230    }
231    else
232    {
233      final LinkedList<String> servers = new LinkedList<>();
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.isEmpty())
247    {
248      usedPrivileges = Collections.emptyList();
249    }
250    else
251    {
252      final LinkedList<String> privileges = new LinkedList<>();
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.isEmpty())
266    {
267      preAuthZUsedPrivileges = Collections.emptyList();
268    }
269    else
270    {
271      final LinkedList<String> privileges = new LinkedList<>();
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.isEmpty())
283    {
284      missingPrivileges = Collections.emptyList();
285    }
286    else
287    {
288      final LinkedList<String> privileges = new LinkedList<>();
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  @Override()
308  public ResultCode getResultCode()
309  {
310    return resultCode;
311  }
312
313
314
315  /**
316   * Retrieves the diagnostic message for the operation.
317   *
318   * @return  The diagnostic message for the operation, or {@code null} if it is
319   *          not included in the log message.
320   */
321  @Override()
322  public String getDiagnosticMessage()
323  {
324    return diagnosticMessage;
325  }
326
327
328
329  /**
330   * Retrieves a message with additional information about the result of the
331   * operation.
332   *
333   * @return  A message with additional information about the result of the
334   *          operation, or {@code null} if it is not included in the log
335   *          message.
336   */
337  @Override()
338  public String getAdditionalInformation()
339  {
340    return additionalInformation;
341  }
342
343
344
345  /**
346   * Retrieves the matched DN for the operation.
347   *
348   * @return  The matched DN for the operation, or {@code null} if it is not
349   *          included in the log message.
350   */
351  @Override()
352  public String getMatchedDN()
353  {
354    return matchedDN;
355  }
356
357
358
359  /**
360   * Retrieves the list of referral URLs for the operation.
361   *
362   * @return  The list of referral URLs for the operation, or an empty list if
363   *          it is not included in the log message.
364   */
365  @Override()
366  public List<String> getReferralURLs()
367  {
368    return referralURLs;
369  }
370
371
372
373  /**
374   * Retrieves a list of the additional servers that were accessed in the course
375   * of processing the operation.  For example, if the access log message is
376   * from a Directory Proxy Server instance, then this may contain a list of the
377   * backend servers used to process the operation.
378   *
379   * @return  A list of the additional servers that were accessed in the course
380   *          of processing the operation, or an empty list if it is not
381   *          included in the log message.
382   */
383  @Override()
384  public List<String> getServersAccessed()
385  {
386    return serversAccessed;
387  }
388
389
390
391  /**
392   * Indicates whether the server accessed any uncached data in the course of
393   * processing the operation.
394   *
395   * @return  {@code true} if the server was known to access uncached data in
396   *          the course of processing the operation, {@code false} if the
397   *          server was known not to access uncached data, or {@code null} if
398   *          it is not included in the log message (and the server likely did
399   *          not access uncached data).
400   */
401  public Boolean getUncachedDataAccessed()
402  {
403    return uncachedDataAccessed;
404  }
405
406
407
408  /**
409   * Retrieves the number of intermediate response messages returned in the
410   * course of processing the operation.
411   *
412   * @return  The number of intermediate response messages returned to the
413   *          client in the course of processing the operation, or {@code null}
414   *          if it is not included in the log message.
415   */
416  @Override()
417  public Long getIntermediateResponsesReturned()
418  {
419    return intermediateResponsesReturned;
420  }
421
422
423
424  /**
425   * Retrieves the length of time in milliseconds required to process the
426   * operation.
427   *
428   * @return  The length of time in milliseconds required to process the
429   *          operation, or {@code null} if it is not included in the log
430   *          message.
431   */
432  @Override()
433  public Double getProcessingTimeMillis()
434  {
435    return processingTime;
436  }
437
438
439
440  /**
441   * Retrieves the length of time in milliseconds the operation was required to
442   * wait on the work queue.
443   *
444   * @return  The length of time in milliseconds the operation was required to
445   *          wait on the work queue, or {@code null} if it is not included in
446   *          the log message.
447   */
448  @Override()
449  public Double getQueueTimeMillis()
450  {
451    return queueTime;
452  }
453
454
455
456  /**
457   * Retrieves the OIDs of any response controls contained in the log message.
458   *
459   * @return  The OIDs of any response controls contained in the log message, or
460   *          an empty list if it is not included in the log message.
461   */
462  @Override()
463  public List<String> getResponseControlOIDs()
464  {
465    return responseControlOIDs;
466  }
467
468
469
470  /**
471   * Retrieves the content of the intermediate client result for the
472   * operation.
473   *
474   * @return  The content of the intermediate client result for the operation,
475   *          or {@code null} if it is not included in the log message.
476   */
477  @Override()
478  public String getIntermediateClientResult()
479  {
480    return intermediateClientResult;
481  }
482
483
484
485  /**
486   * Retrieves the OID for the extended response.
487   *
488   * @return  The OID for the extended response, or {@code null} if it is not
489   *          included in the log message.
490   */
491  public String getResponseOID()
492  {
493    return responseOID;
494  }
495
496
497
498  /**
499   * Retrieves the address of the backend server to which the request has been
500   * forwarded.
501   *
502   * @return  The address of the backend server to which the request has been
503   *          forwarded, or {@code null} if it is not included in the log
504   *          message.
505   */
506  public String getTargetHost()
507  {
508    return targetHost;
509  }
510
511
512
513  /**
514   * Retrieves the port of the backend server to which the request has been
515   * forwarded.
516   *
517   * @return  The port of the backend server to which the request has been
518   *          forwarded, or {@code null} if it is not included in the log
519   *          message.
520   */
521  public Integer getTargetPort()
522  {
523    return targetPort;
524  }
525
526
527
528  /**
529   * Retrieves the protocol used to forward the request to the backend server.
530   *
531   * @return  The protocol used to forward the request to the backend server, or
532   *          {@code null} if it is not included in the log message.
533   */
534  public String getTargetProtocol()
535  {
536    return targetProtocol;
537  }
538
539
540
541  /**
542   * Retrieves the name of the client connection policy that was selected for
543   * the client connection.
544   *
545   * @return  The name of the client connection policy that was selected for the
546   *          client connection, or {@code null} if it is not included in the
547   *          log message.
548   */
549  public String getClientConnectionPolicy()
550  {
551    return clientConnectionPolicy;
552  }
553
554
555
556  /**
557   * Retrieves the names of any privileges used during the course of processing
558   * the operation.
559   *
560   * @return  The names of any privileges used during the course of processing
561   *          the operation, or an empty list if no privileges were used or this
562   *          is not included in the log message.
563   */
564  public List<String> getUsedPrivileges()
565  {
566    return usedPrivileges;
567  }
568
569
570
571  /**
572   * Retrieves the names of any privileges used during the course of processing
573   * the operation before an alternate authorization identity was assigned.
574   *
575   * @return  The names of any privileges used during the course of processing
576   *          the operation before an alternate authorization identity was
577   *          assigned, or an empty list if no privileges were used or this is
578   *          not included in the log message.
579   */
580  public List<String> getPreAuthorizationUsedPrivileges()
581  {
582    return preAuthZUsedPrivileges;
583  }
584
585
586
587  /**
588   * Retrieves the names of any privileges that would have been required for
589   * processing the operation but that the requester did not have.
590   *
591   * @return  The names of any privileges that would have been required for
592   *          processing the operation but that the requester did not have, or
593   *          an empty list if there were no missing privileges or this is not
594   *          included in the log message.
595   */
596  public List<String> getMissingPrivileges()
597  {
598    return missingPrivileges;
599  }
600
601
602
603  /**
604   * {@inheritDoc}
605   */
606  @Override()
607  public AccessLogMessageType getMessageType()
608  {
609    return AccessLogMessageType.RESULT;
610  }
611}