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