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 Alcatel-Lucent 8661 046 * server products. These classes provide support for proprietary 047 * functionality or for external specifications that are not considered stable 048 * or mature enough to be guaranteed to work in an interoperable way with 049 * 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.length() == 0)) 197 { 198 referralURLs = Collections.emptyList(); 199 } 200 else 201 { 202 final LinkedList<String> refs = new LinkedList<String>(); 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<String>(); 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.length() == 0)) 239 { 240 serversAccessed = Collections.emptyList(); 241 } 242 else 243 { 244 final LinkedList<String> servers = new LinkedList<String>(); 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.length() == 0)) 258 { 259 usedPrivileges = Collections.emptyList(); 260 } 261 else 262 { 263 final LinkedList<String> privileges = new LinkedList<String>(); 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.length() == 0)) 277 { 278 preAuthZUsedPrivileges = Collections.emptyList(); 279 } 280 else 281 { 282 final LinkedList<String> privileges = new LinkedList<String>(); 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.length() == 0)) 294 { 295 missingPrivileges = Collections.emptyList(); 296 } 297 else 298 { 299 final LinkedList<String> privileges = new LinkedList<String>(); 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.length() == 0)) 312 { 313 indexesWithKeysAccessedNearEntryLimit = Collections.emptyList(); 314 } 315 else 316 { 317 final LinkedList<String> indexes = new LinkedList<String>(); 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.length() == 0)) 331 { 332 indexesWithKeysAccessedOverEntryLimit = Collections.emptyList(); 333 } 334 else 335 { 336 final LinkedList<String> indexes = new LinkedList<String>(); 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 public ResultCode getResultCode() 357 { 358 return resultCode; 359 } 360 361 362 363 /** 364 * Retrieves the diagnostic message for the operation. 365 * 366 * @return The diagnostic message for the operation, or {@code null} if it is 367 * not included in the log message. 368 */ 369 public String getDiagnosticMessage() 370 { 371 return diagnosticMessage; 372 } 373 374 375 376 /** 377 * Retrieves a message with additional information about the result of the 378 * operation. 379 * 380 * @return A message with additional information about the result of the 381 * operation, or {@code null} if it is not included in the log 382 * message. 383 */ 384 public String getAdditionalInformation() 385 { 386 return additionalInformation; 387 } 388 389 390 391 /** 392 * Retrieves the matched DN for the operation. 393 * 394 * @return The matched DN for the operation, or {@code null} if it is not 395 * included in the log message. 396 */ 397 public String getMatchedDN() 398 { 399 return matchedDN; 400 } 401 402 403 404 /** 405 * Retrieves the list of referral URLs for the operation. 406 * 407 * @return The list of referral URLs for the operation, or an empty list if 408 * it is not included in the log message. 409 */ 410 public List<String> getReferralURLs() 411 { 412 return referralURLs; 413 } 414 415 416 417 /** 418 * Retrieves the number of intermediate response messages returned in the 419 * course of processing the operation. 420 * 421 * @return The number of intermediate response messages returned to the 422 * client in the course of processing the operation, or {@code null} 423 * if it is not included in the log message. 424 */ 425 public Long getIntermediateResponsesReturned() 426 { 427 return intermediateResponsesReturned; 428 } 429 430 431 432 /** 433 * Retrieves the length of time in milliseconds required to process the 434 * operation. 435 * 436 * @return The length of time in milliseconds required to process the 437 * operation, or {@code null} if it is not included in the log 438 * message. 439 */ 440 public Double getProcessingTimeMillis() 441 { 442 return processingTime; 443 } 444 445 446 447 /** 448 * Retrieves the length of time in milliseconds the operation was required to 449 * wait on the work queue. 450 * 451 * @return The length of time in milliseconds the operation was required to 452 * wait on the work queue, or {@code null} if it is not included in 453 * the log message. 454 */ 455 public Double getQueueTimeMillis() 456 { 457 return queueTime; 458 } 459 460 461 462 /** 463 * Retrieves the OIDs of any response controls contained in the log message. 464 * 465 * @return The OIDs of any response controls contained in the log message, or 466 * an empty list if it is not included in the log message. 467 */ 468 public List<String> getResponseControlOIDs() 469 { 470 return responseControlOIDs; 471 } 472 473 474 475 /** 476 * Retrieves a list of the additional servers that were accessed in the course 477 * of processing the operation. For example, if the access log message is 478 * from a Directory Proxy Server instance, then this may contain a list of the 479 * backend servers used to process the operation. 480 * 481 * @return A list of the additional servers that were accessed in the course 482 * of processing the operation, or an empty list if it is not 483 * included in the log message. 484 */ 485 public List<String> getServersAccessed() 486 { 487 return serversAccessed; 488 } 489 490 491 492 /** 493 * Indicates whether the server accessed any uncached data in the course of 494 * processing the operation. 495 * 496 * @return {@code true} if the server was known to access uncached data in 497 * the course of processing the operation, {@code false} if the 498 * server was known not to access uncached data, or {@code null} if 499 * it is not included in the log message (and the server likely did 500 * not access uncached data). 501 */ 502 public Boolean getUncachedDataAccessed() 503 { 504 return uncachedDataAccessed; 505 } 506 507 508 509 /** 510 * Retrieves the content of the intermediate client result for the 511 * operation. 512 * 513 * @return The content of the intermediate client result for the operation, 514 * or {@code null} if it is not included in the log message. 515 */ 516 public String getIntermediateClientResult() 517 { 518 return intermediateClientResult; 519 } 520 521 522 523 /** 524 * Retrieves the number of entries returned to the client. 525 * 526 * @return The number of entries returned to the client, or {@code null} if 527 * it is not included in the log message. 528 */ 529 public Long getEntriesReturned() 530 { 531 return entriesReturned; 532 } 533 534 535 536 /** 537 * Indicates whether the search was unindexed. 538 * 539 * @return {@code Boolean.TRUE} if the search was unindexed, 540 * {@code Boolean.FALSE} if it was not, or {@code null} if it is not 541 * included in the log message. 542 */ 543 public Boolean isUnindexed() 544 { 545 return isUnindexed; 546 } 547 548 549 550 /** 551 * Retrieves the alternate authorization DN for the operation. 552 * 553 * @return The alternate authorization DN for the operation, or {@code null} 554 * if it is not included in the log message. 555 */ 556 public String getAlternateAuthorizationDN() 557 { 558 return authzDN; 559 } 560 561 562 563 /** 564 * Retrieves the address of the backend server to which the request has been 565 * forwarded. 566 * 567 * @return The address of the backend server to which the request has been 568 * forwarded, or {@code null} if it is not included in the log 569 * message. 570 */ 571 public String getTargetHost() 572 { 573 return targetHost; 574 } 575 576 577 578 /** 579 * Retrieves the port of the backend server to which the request has been 580 * forwarded. 581 * 582 * @return The port of the backend server to which the request has been 583 * forwarded, or {@code null} if it is not included in the log 584 * message. 585 */ 586 public Integer getTargetPort() 587 { 588 return targetPort; 589 } 590 591 592 593 /** 594 * Retrieves the protocol used to forward the request to the backend server. 595 * 596 * @return The protocol used to forward the request to the backend server, or 597 * {@code null} if it is not included in the log message. 598 */ 599 public String getTargetProtocol() 600 { 601 return targetProtocol; 602 } 603 604 605 606 /** 607 * Retrieves the names of any privileges used during the course of processing 608 * the operation. 609 * 610 * @return The names of any privileges used during the course of processing 611 * the operation, or an empty list if no privileges were used or this 612 * is not included in the log message. 613 */ 614 public List<String> getUsedPrivileges() 615 { 616 return usedPrivileges; 617 } 618 619 620 621 /** 622 * Retrieves the names of any privileges used during the course of processing 623 * the operation before an alternate authorization identity was assigned. 624 * 625 * @return The names of any privileges used during the course of processing 626 * the operation before an alternate authorization identity was 627 * assigned, or an empty list if no privileges were used or this is 628 * not included in the log message. 629 */ 630 public List<String> getPreAuthorizationUsedPrivileges() 631 { 632 return preAuthZUsedPrivileges; 633 } 634 635 636 637 /** 638 * Retrieves the names of any privileges that would have been required for 639 * processing the operation but that the requester did not have. 640 * 641 * @return The names of any privileges that would have been required for 642 * processing the operation but that the requester did not have, or 643 * an empty list if there were no missing privileges or this is not 644 * included in the log message. 645 */ 646 public List<String> getMissingPrivileges() 647 { 648 return missingPrivileges; 649 } 650 651 652 653 /** 654 * Retrieves the names of any indexes for which one or more keys near 655 * (typically, within 80% of) the index entry limit were accessed while 656 * processing the operation. 657 * 658 * @return The names of any indexes for which one or more keys near the index 659 * entry limit were accessed while processing the operation, or an 660 * empty list if no such index keys were accessed, or if this is not 661 * included in the log message. 662 */ 663 public List<String> getIndexesWithKeysAccessedNearEntryLimit() 664 { 665 return indexesWithKeysAccessedNearEntryLimit; 666 } 667 668 669 670 /** 671 * Retrieves the names of any indexes for which one or more keys over the 672 * index entry limit were accessed while processing the operation. 673 * 674 * @return The names of any indexes for which one or more keys over the index 675 * entry limit were accessed while processing the operation, or an 676 * empty list if no such index keys were accessed, or if this is not 677 * included in the log message. 678 */ 679 public List<String> getIndexesWithKeysAccessedOverEntryLimit() 680 { 681 return indexesWithKeysAccessedOverEntryLimit; 682 } 683 684 685 686 /** 687 * {@inheritDoc} 688 */ 689 @Override() 690 public AccessLogMessageType getMessageType() 691 { 692 return AccessLogMessageType.RESULT; 693 } 694}