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 Alcatel-Lucent 8661 050 * server products. These classes provide support for proprietary 051 * functionality or for external specifications that are not considered stable 052 * or mature enough to be guaranteed to work in an interoperable way with 053 * 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.length() == 0)) 216 { 217 referralURLs = Collections.emptyList(); 218 } 219 else 220 { 221 final LinkedList<String> refs = new LinkedList<String>(); 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<String>(); 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.length() == 0)) 258 { 259 serversAccessed = Collections.emptyList(); 260 } 261 else 262 { 263 final LinkedList<String> servers = new LinkedList<String>(); 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.length() == 0)) 305 { 306 usedPrivileges = Collections.emptyList(); 307 } 308 else 309 { 310 final LinkedList<String> privileges = new LinkedList<String>(); 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.length() == 0)) 324 { 325 preAuthZUsedPrivileges = Collections.emptyList(); 326 } 327 else 328 { 329 final LinkedList<String> privileges = new LinkedList<String>(); 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.length() == 0)) 341 { 342 missingPrivileges = Collections.emptyList(); 343 } 344 else 345 { 346 final LinkedList<String> privileges = new LinkedList<String>(); 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.length() == 0)) 359 { 360 indexesWithKeysAccessedNearEntryLimit = Collections.emptyList(); 361 } 362 else 363 { 364 final LinkedList<String> indexes = new LinkedList<String>(); 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.length() == 0)) 378 { 379 indexesWithKeysAccessedOverEntryLimit = Collections.emptyList(); 380 } 381 else 382 { 383 final LinkedList<String> indexes = new LinkedList<String>(); 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 public ResultCode getResultCode() 404 { 405 return resultCode; 406 } 407 408 409 410 /** 411 * Retrieves the diagnostic message for the operation. 412 * 413 * @return The diagnostic message for the operation, or {@code null} if it is 414 * not included in the log message. 415 */ 416 public String getDiagnosticMessage() 417 { 418 return diagnosticMessage; 419 } 420 421 422 423 /** 424 * Retrieves a message with additional information about the result of the 425 * operation. 426 * 427 * @return A message with additional information about the result of the 428 * operation, or {@code null} if it is not included in the log 429 * message. 430 */ 431 public String getAdditionalInformation() 432 { 433 return additionalInformation; 434 } 435 436 437 438 /** 439 * Retrieves the matched DN for the operation. 440 * 441 * @return The matched DN for the operation, or {@code null} if it is not 442 * included in the log message. 443 */ 444 public String getMatchedDN() 445 { 446 return matchedDN; 447 } 448 449 450 451 /** 452 * Retrieves the list of referral URLs for the operation. 453 * 454 * @return The list of referral URLs for the operation, or an empty list if 455 * it is not included in the log message. 456 */ 457 public List<String> getReferralURLs() 458 { 459 return referralURLs; 460 } 461 462 463 464 /** 465 * Retrieves the number of intermediate response messages returned in the 466 * course of processing the operation. 467 * 468 * @return The number of intermediate response messages returned to the 469 * client in the course of processing the operation, or {@code null} 470 * if it is not included in the log message. 471 */ 472 public Long getIntermediateResponsesReturned() 473 { 474 return intermediateResponsesReturned; 475 } 476 477 478 479 /** 480 * Retrieves the length of time in milliseconds required to process the 481 * operation. 482 * 483 * @return The length of time in milliseconds required to process the 484 * operation, or {@code null} if it is not included in the log 485 * message. 486 */ 487 public Double getProcessingTimeMillis() 488 { 489 return processingTime; 490 } 491 492 493 494 /** 495 * Retrieves the length of time in milliseconds the operation was required to 496 * wait on the work queue. 497 * 498 * @return The length of time in milliseconds the operation was required to 499 * wait on the work queue, or {@code null} if it is not included in 500 * the log message. 501 */ 502 public Double getQueueTimeMillis() 503 { 504 return queueTime; 505 } 506 507 508 509 /** 510 * Retrieves the OIDs of any response controls contained in the log message. 511 * 512 * @return The OIDs of any response controls contained in the log message, or 513 * an empty list if it is not included in the log message. 514 */ 515 public List<String> getResponseControlOIDs() 516 { 517 return responseControlOIDs; 518 } 519 520 521 522 /** 523 * Retrieves a list of the additional servers that were accessed in the course 524 * of processing the operation. For example, if the access log message is 525 * from a Directory Proxy Server instance, then this may contain a list of the 526 * backend servers used to process the operation. 527 * 528 * @return A list of the additional servers that were accessed in the course 529 * of processing the operation, or an empty list if it is not 530 * included in the log message. 531 */ 532 public List<String> getServersAccessed() 533 { 534 return serversAccessed; 535 } 536 537 538 539 /** 540 * Indicates whether the server accessed any uncached data in the course of 541 * processing the operation. 542 * 543 * @return {@code true} if the server was known to access uncached data in 544 * the course of processing the operation, {@code false} if the 545 * server was known not to access uncached data, or {@code null} if 546 * it is not included in the log message (and the server likely did 547 * not access uncached data). 548 */ 549 public Boolean getUncachedDataAccessed() 550 { 551 return uncachedDataAccessed; 552 } 553 554 555 556 /** 557 * Retrieves the content of the intermediate client result for the 558 * operation. 559 * 560 * @return The content of the intermediate client result for the operation, 561 * or {@code null} if it is not included in the log message. 562 */ 563 public String getIntermediateClientResult() 564 { 565 return intermediateClientResult; 566 } 567 568 569 570 /** 571 * Retrieves the alternate authorization DN for the operation. 572 * 573 * @return The alternate authorization DN for the operation, or {@code null} 574 * if it is not included in the log message. 575 */ 576 public String getAlternateAuthorizationDN() 577 { 578 return authzDN; 579 } 580 581 582 583 /** 584 * Retrieves the replication change ID for the operation, if available. 585 * 586 * @return The replication change ID for the operation, or {@code null} if it 587 * is not included in the log message. 588 */ 589 public String getReplicationChangeID() 590 { 591 return replicationChangeID; 592 } 593 594 595 596 /** 597 * Indicates whether the modify operation targeted a soft-deleted entry. 598 * 599 * @return {@code true} if the modify operation was known to target a 600 * soft-deleted entry, {@code false} if it was known to target a 601 * non-soft-deleted entry, or {@code null} if it is not included in 602 * the log message (and likely did not target a soft-deleted entry). 603 */ 604 public Boolean getChangeToSoftDeletedEntry() 605 { 606 return changeToSoftDeletedEntry; 607 } 608 609 610 611 /** 612 * Retrieves the address of the backend server to which the request has been 613 * forwarded. 614 * 615 * @return The address of the backend server to which the request has been 616 * forwarded, or {@code null} if it is not included in the log 617 * message. 618 */ 619 public String getTargetHost() 620 { 621 return targetHost; 622 } 623 624 625 626 /** 627 * Retrieves the port of the backend server to which the request has been 628 * forwarded. 629 * 630 * @return The port of the backend server to which the request has been 631 * forwarded, or {@code null} if it is not included in the log 632 * message. 633 */ 634 public Integer getTargetPort() 635 { 636 return targetPort; 637 } 638 639 640 641 /** 642 * Retrieves the protocol used to forward the request to the backend server. 643 * 644 * @return The protocol used to forward the request to the backend server, or 645 * {@code null} if it is not included in the log message. 646 */ 647 public String getTargetProtocol() 648 { 649 return targetProtocol; 650 } 651 652 653 654 /** 655 * Retrieves the local level that will be used for assured replication 656 * processing, if available. 657 * 658 * @return The local level that will be used for assured replication 659 * processing, or {@code null} if this is not included in the log 660 * message (e.g., because assured replication will not be performed 661 * for the operation). 662 */ 663 public AssuredReplicationLocalLevel getAssuredReplicationLocalLevel() 664 { 665 return assuredReplicationLocalLevel; 666 } 667 668 669 670 /** 671 * Retrieves the remote level that will be used for assured replication 672 * processing, if available. 673 * 674 * @return The remote level that will be used for assured replication 675 * processing, or {@code null} if this is not included in the log 676 * message (e.g., because assured replication will not be performed 677 * for the operation). 678 */ 679 public AssuredReplicationRemoteLevel getAssuredReplicationRemoteLevel() 680 { 681 return assuredReplicationRemoteLevel; 682 } 683 684 685 686 /** 687 * Retrieves the maximum length of time in milliseconds that the server will 688 * delay the response to the client while waiting for the replication 689 * assurance requirement to be satisfied. 690 * 691 * @return The maximum length of time in milliseconds that the server will 692 * delay the response to the client while waiting for the replication 693 * assurance requirement to be satisfied, or {@code null} if this is 694 * not included in the log message (e.g., because assured replication 695 * will not be performed for the operation). 696 */ 697 public Long getAssuredReplicationTimeoutMillis() 698 { 699 return assuredReplicationTimeoutMillis; 700 } 701 702 703 704 /** 705 * Indicates whether the operation response to the client will be delayed 706 * until replication assurance has been satisfied or the timeout has occurred. 707 * 708 * @return {@code true} if the operation response to the client will be 709 * delayed until replication assurance has been satisfied, 710 * {@code false} if the response will not be delayed by assurance 711 * processing, or {@code null} if this was not included in the 712 * log message (e.g., because assured replication will not be 713 * performed for the operation) 714 */ 715 public Boolean getResponseDelayedByAssurance() 716 { 717 return responseDelayedByAssurance; 718 } 719 720 721 722 /** 723 * Retrieves the names of any privileges used during the course of processing 724 * the operation. 725 * 726 * @return The names of any privileges used during the course of processing 727 * the operation, or an empty list if no privileges were used or this 728 * is not included in the log message. 729 */ 730 public List<String> getUsedPrivileges() 731 { 732 return usedPrivileges; 733 } 734 735 736 737 /** 738 * Retrieves the names of any privileges used during the course of processing 739 * the operation before an alternate authorization identity was assigned. 740 * 741 * @return The names of any privileges used during the course of processing 742 * the operation before an alternate authorization identity was 743 * assigned, or an empty list if no privileges were used or this is 744 * not included in the log message. 745 */ 746 public List<String> getPreAuthorizationUsedPrivileges() 747 { 748 return preAuthZUsedPrivileges; 749 } 750 751 752 753 /** 754 * Retrieves the names of any privileges that would have been required for 755 * processing the operation but that the requester did not have. 756 * 757 * @return The names of any privileges that would have been required for 758 * processing the operation but that the requester did not have, or 759 * an empty list if there were no missing privileges or this is not 760 * included in the log message. 761 */ 762 public List<String> getMissingPrivileges() 763 { 764 return missingPrivileges; 765 } 766 767 768 769 /** 770 * Retrieves the names of any indexes for which one or more keys near 771 * (typically, within 80% of) the index entry limit were accessed while 772 * processing the operation. 773 * 774 * @return The names of any indexes for which one or more keys near the index 775 * entry limit were accessed while processing the operation, or an 776 * empty list if no such index keys were accessed, or if this is not 777 * included in the log message. 778 */ 779 public List<String> getIndexesWithKeysAccessedNearEntryLimit() 780 { 781 return indexesWithKeysAccessedNearEntryLimit; 782 } 783 784 785 786 /** 787 * Retrieves the names of any indexes for which one or more keys over the 788 * index entry limit were accessed while processing the operation. 789 * 790 * @return The names of any indexes for which one or more keys over the index 791 * entry limit were accessed while processing the operation, or an 792 * empty list if no such index keys were accessed, or if this is not 793 * included in the log message. 794 */ 795 public List<String> getIndexesWithKeysAccessedOverEntryLimit() 796 { 797 return indexesWithKeysAccessedOverEntryLimit; 798 } 799 800 801 802 /** 803 * {@inheritDoc} 804 */ 805 @Override() 806 public AccessLogMessageType getMessageType() 807 { 808 return AccessLogMessageType.RESULT; 809 } 810}