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