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