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