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