001 /* 002 * CDDL HEADER START 003 * 004 * The contents of this file are subject to the terms of the 005 * Common Development and Distribution License, Version 1.0 only 006 * (the "License"). You may not use this file except in compliance 007 * with the License. 008 * 009 * You can obtain a copy of the license at 010 * trunk/opends/resource/legal-notices/OpenDS.LICENSE 011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE. 012 * See the License for the specific language governing permissions 013 * and limitations under the License. 014 * 015 * When distributing Covered Code, include this CDDL HEADER in each 016 * file and include the License file at 017 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, 018 * add the following below this CDDL HEADER, with the fields enclosed 019 * by brackets "[]" replaced with your own identifying information: 020 * Portions Copyright [yyyy] [name of copyright owner] 021 * 022 * CDDL HEADER END 023 * 024 * 025 * Copyright 2006-2008 Sun Microsystems, Inc. 026 */ 027 package org.opends.server.types; 028 import org.opends.messages.Message; 029 import org.opends.messages.MessageBuilder; 030 031 032 import static org.opends.server.core.CoreConstants.*; 033 034 import java.util.ArrayList; 035 import java.util.HashMap; 036 import java.util.List; 037 import java.util.Map; 038 import org.opends.server.api.ClientConnection; 039 import org.opends.server.types.operation.PostResponseOperation; 040 import org.opends.server.types.operation.PreParseOperation; 041 import org.opends.server.core.DirectoryServer; 042 import static org.opends.server.loggers.debug. 043 DebugLogger.debugEnabled; 044 import static org.opends.server.loggers.debug.DebugLogger.getTracer; 045 import org.opends.server.loggers.debug.DebugTracer; 046 047 048 /** 049 * This class defines a generic operation that may be processed by the 050 * Directory Server. Specific subclasses should implement specific 051 * functionality appropriate for the type of operation. 052 * <BR><BR> 053 * Note that this class is not intended to be subclassed by any 054 * third-party code outside of the OpenDS project. It should only be 055 * extended by the operation types included in the 056 * {@code org.opends.server.core} package. 057 */ 058 @org.opends.server.types.PublicAPI( 059 stability=org.opends.server.types.StabilityLevel.VOLATILE, 060 mayInstantiate=false, 061 mayExtend=false, 062 mayInvoke=true) 063 public abstract class AbstractOperation 064 implements Operation, PreParseOperation, PostResponseOperation, 065 Runnable 066 { 067 /** 068 * The tracer object for the debug logger. 069 */ 070 private static final DebugTracer TRACER = getTracer(); 071 072 /** 073 * The set of response controls that will always be returned for 074 * an abandon operation. 075 */ 076 protected static final List<Control> NO_RESPONSE_CONTROLS = 077 new ArrayList<Control>(0); 078 079 080 /** 081 * The client connection with which this operation is associated. 082 */ 083 protected final ClientConnection clientConnection; 084 085 086 /** 087 * The message ID for this operation. 088 */ 089 protected final int messageID; 090 091 092 093 /** 094 * The operation ID for this operation. 095 */ 096 protected final long operationID; 097 098 099 /** 100 * Wether nanotime was used for this operation. 101 */ 102 protected final boolean useNanoTime; 103 104 105 /** 106 * The cancel request for this operation. 107 */ 108 protected CancelRequest cancelRequest; 109 110 111 /** 112 * The cancel result for this operation. 113 */ 114 protected CancelResult cancelResult; 115 116 // Indicates whether this is an internal operation triggered within 117 // the server itself rather than requested by an external client. 118 private boolean isInternalOperation; 119 120 // Indicates whether this operation is involved in data 121 // synchronization processing. 122 private boolean isSynchronizationOperation; 123 124 // The matched DN for this operation. 125 private DN matchedDN; 126 127 // The entry for the authorization identify for this operation. 128 private Entry authorizationEntry; 129 130 // A set of attachments associated with this operation that might 131 // be used by various components during its processing. 132 private Map<String,Object> attachments; 133 134 // The set of controls included in the request from the client. 135 private List<Control> requestControls; 136 137 // The set of referral URLs for this operation. 138 private List<String> referralURLs; 139 140 // The result code for this operation. 141 private ResultCode resultCode; 142 143 // Additional information that should be included in the log but 144 // not sent to the client. 145 private MessageBuilder additionalLogMessage; 146 147 // The error message for this operation that should be included in 148 // the log and in the response to the client. 149 private MessageBuilder errorMessage; 150 151 // Indicates whether this operation nneds to be synchronized to 152 // other copies of the data. 153 private boolean dontSynchronizeFlag; 154 155 // The time that processing started on this operation in 156 // milliseconds. 157 private long processingStartTime; 158 159 // The time that processing ended on this operation in 160 // milliseconds. 161 private long processingStopTime; 162 163 // The time that processing started on this operation in 164 // nanoseconds. 165 private long processingStartNanoTime; 166 167 // The time that processing ended on this operation in 168 // nanoseconds. 169 private long processingStopNanoTime; 170 171 /** 172 * Creates a new operation with the provided information. 173 * 174 * @param clientConnection The client connection with which this 175 * operation is associated. 176 * @param operationID The identifier assigned to this 177 * operation for the client connection. 178 * @param messageID The message ID of the request with 179 * which this operation is associated. 180 * @param requestControls The set of controls included in the 181 * request. 182 */ 183 protected AbstractOperation(ClientConnection clientConnection, 184 long operationID, 185 int messageID, List<Control> requestControls) 186 { 187 this.clientConnection = clientConnection; 188 this.operationID = operationID; 189 this.messageID = messageID; 190 this.useNanoTime = DirectoryServer.getUseNanoTime(); 191 192 if (requestControls == null) 193 { 194 this.requestControls = new ArrayList<Control>(0); 195 } 196 else 197 { 198 this.requestControls = requestControls; 199 } 200 201 resultCode = ResultCode.UNDEFINED; 202 additionalLogMessage = new MessageBuilder(); 203 errorMessage = new MessageBuilder(); 204 attachments = new HashMap<String,Object>(); 205 matchedDN = null; 206 referralURLs = null; 207 cancelResult = null; 208 isInternalOperation = false; 209 isSynchronizationOperation = false; 210 authorizationEntry = 211 clientConnection.getAuthenticationInfo(). 212 getAuthorizationEntry(); 213 } 214 215 216 217 /** 218 * Retrieves the operation type for this operation. 219 * 220 * @return The operation type for this operation. 221 */ 222 public abstract OperationType getOperationType(); 223 224 225 226 /** 227 * Terminates the client connection being used to process this 228 * operation. If this is called by a plugin, then that plugin must 229 * return a result indicating that the client connection has been 230 * teriminated. 231 * 232 * @param disconnectReason The disconnect reason that provides the 233 * generic cause for the disconnect. 234 * @param sendNotification Indicates whether to try to provide 235 * notification 236 * to the client that the connection will 237 * be closed. 238 * @param message The message to send to the client. It 239 * may be {@code null} if no notification 240 * is to be sent. 241 */ 242 public void disconnectClient(DisconnectReason disconnectReason, 243 boolean sendNotification, 244 Message message) 245 { 246 clientConnection.disconnect(disconnectReason, sendNotification, 247 message); 248 } 249 250 251 252 /** 253 * Retrieves a set of standard elements that should be logged in all 254 * requests and responses for all types of operations. Each element 255 * in the array will itself be a two-element array in which the 256 * first element is the name of the field and the second is a string 257 * representation of the value, or {@code null} if there is no value 258 * for that field. 259 * 260 * @return A standard set of elements that should be logged in 261 * requests and responses for all types of operations. 262 */ 263 public final String[][] getCommonLogElements() 264 { 265 // Note that no debugging will be done in this method because 266 // it is a likely candidate for being called by the logging 267 // subsystem. 268 269 return new String[][] 270 { 271 new String[] { LOG_ELEMENT_CONNECTION_ID, 272 String.valueOf(getConnectionID()) }, 273 new String[] { LOG_ELEMENT_OPERATION_ID, 274 String.valueOf(operationID) }, 275 new String[] { LOG_ELEMENT_MESSAGE_ID, 276 String.valueOf(messageID) } 277 }; 278 } 279 280 281 282 /** 283 * Retrieves a standard set of elements that should be logged in 284 * requests for this type of operation. Each element in the array 285 * will itself be a two-element array in which the first element is 286 * the name of the field and the second is a string representation 287 * of the value, or {@code null} if there is no value for that 288 * field. 289 * 290 * @return A standard set of elements that should be logged in 291 * requests for this type of operation. 292 */ 293 public abstract String[][] getRequestLogElements(); 294 295 296 297 /** 298 * Retrieves a standard set of elements that should be logged in 299 * responses for this type of operation. Each element in the array 300 * will itself be a two-element array in which the first element is 301 * the name of the field and the second is a string representation 302 * of the value, or {@code null} if there is no value for that 303 * field. 304 * 305 * @return A standard set of elements that should be logged in 306 * responses for this type of operation. 307 */ 308 public abstract String[][] getResponseLogElements(); 309 310 311 312 /** 313 * Retrieves the client connection with which this operation is 314 * associated. 315 * 316 * @return The client connection with which this operation is 317 * associated. 318 */ 319 public final ClientConnection getClientConnection() 320 { 321 return clientConnection; 322 } 323 324 325 326 /** 327 * Retrieves the unique identifier that is assigned to the client 328 * connection that submitted this operation. 329 * 330 * @return The unique identifier that is assigned to the client 331 * connection that submitted this operation. 332 */ 333 public final long getConnectionID() 334 { 335 return clientConnection.getConnectionID(); 336 } 337 338 339 340 /** 341 * Retrieves the operation ID for this operation. 342 * 343 * @return The operation ID for this operation. 344 */ 345 public final long getOperationID() 346 { 347 return operationID; 348 } 349 350 351 352 /** 353 * Retrieves the message ID assigned to this operation. 354 * 355 * @return The message ID assigned to this operation. 356 */ 357 public final int getMessageID() 358 { 359 return messageID; 360 } 361 362 363 364 /** 365 * Retrieves the set of controls included in the request from the 366 * client. The returned list must not be altered. 367 * 368 * @return The set of controls included in the request from the 369 * client. 370 */ 371 public final List<Control> getRequestControls() 372 { 373 return requestControls; 374 } 375 376 377 378 /** 379 * Adds the provided control to the set of request controls for this 380 * operation. This method may only be called by pre-parse plugins. 381 * 382 * @param control The control to add to the set of request 383 * controls for this operation. 384 */ 385 public final void addRequestControl(Control control) 386 { 387 requestControls.add(control); 388 } 389 390 391 392 /** 393 * Removes the provided control from the set of request controls for 394 * this operation. This method may only be called by pre-parse 395 * plugins. 396 * 397 * @param control The control to remove from the set of request 398 * controls for this operation. 399 */ 400 public final void removeRequestControl(Control control) 401 { 402 requestControls.remove(control); 403 } 404 405 406 407 /** 408 * Retrieves the set of controls to include in the response to the 409 * client. The contents of this list must not be altered. 410 * 411 * @return The set of controls to include in the response to the 412 * client. 413 */ 414 public abstract List<Control> getResponseControls(); 415 416 417 418 /** 419 * Adds the provided control to the set of controls to include in 420 * the response to the client. This method may not be called by 421 * post-response plugins. 422 * 423 * @param control The control to add to the set of controls to 424 * include in the response to the client. 425 */ 426 public abstract void addResponseControl(Control control); 427 428 429 430 /** 431 * Removes the provided control from the set of controls to include 432 * in the response to the client. This method may not be called by 433 * post-response plugins. 434 * 435 * @param control The control to remove from the set of controls 436 * to include in the response to the client. 437 */ 438 public abstract void removeResponseControl(Control control); 439 440 441 442 /** 443 * Retrieves the result code for this operation. 444 * 445 * @return The result code associated for this operation, or 446 * {@code UNDEFINED} if the operation has not yet 447 * completed. 448 */ 449 public final ResultCode getResultCode() 450 { 451 return resultCode; 452 } 453 454 455 456 /** 457 * Specifies the result code for this operation. This method may 458 * not be called by post-response plugins. 459 * 460 * @param resultCode The result code for this operation. 461 */ 462 public final void setResultCode(ResultCode resultCode) 463 { 464 this.resultCode = resultCode; 465 } 466 467 468 469 /** 470 * Retrieves the error message for this operation. Its contents may 471 * be altered by pre-parse, pre-operation, and post-operation 472 * plugins, but not by post-response plugins. 473 * 474 * @return The error message for this operation. 475 */ 476 public final MessageBuilder getErrorMessage() 477 { 478 return errorMessage; 479 } 480 481 482 483 /** 484 * Specifies the error message for this operation. This method may 485 * not be called by post-response plugins. 486 * 487 * @param errorMessage The error message for this operation. 488 */ 489 public final void setErrorMessage(MessageBuilder errorMessage) 490 { 491 if (errorMessage == null) 492 { 493 this.errorMessage = new MessageBuilder(); 494 } 495 else 496 { 497 this.errorMessage = errorMessage; 498 } 499 } 500 501 502 503 /** 504 * Appends the provided message to the error message buffer. If the 505 * buffer has not yet been created, then this will create it first 506 * and then add the provided message. This method may not be called 507 * by post-response plugins. 508 * 509 * @param message The message to append to the error message 510 * buffer. 511 */ 512 public final void appendErrorMessage(Message message) 513 { 514 if (errorMessage == null) 515 { 516 errorMessage = new MessageBuilder(message); 517 } 518 else 519 { 520 if (errorMessage.length() > 0) 521 { 522 errorMessage.append(" "); 523 } 524 525 errorMessage.append(message); 526 } 527 } 528 529 530 531 /** 532 * Retrieves the additional log message for this operation, which 533 * should be written to the log but not included in the response to 534 * the client. The contents of this buffer may be altered by 535 * pre-parse, pre-operation, and post-operation plugins, but not by 536 * post-response plugins. 537 * 538 * @return The additional log message for this operation. 539 */ 540 public final MessageBuilder getAdditionalLogMessage() 541 { 542 return additionalLogMessage; 543 } 544 545 546 547 /** 548 * Specifies the additional log message for this operation, which 549 * should be written to the log but not included in the response to 550 * the client. This method may not be called by post-response 551 * plugins. 552 * 553 * @param additionalLogMessage The additional log message for this 554 * operation. 555 */ 556 public final void setAdditionalLogMessage( 557 MessageBuilder additionalLogMessage) 558 { 559 if (additionalLogMessage == null) 560 { 561 this.additionalLogMessage = new MessageBuilder(); 562 } 563 else 564 { 565 this.additionalLogMessage = additionalLogMessage; 566 } 567 } 568 569 570 571 /** 572 * Appends the provided message to the additional log information 573 * for this operation. This method may not be called by 574 * post-response plugins. 575 * 576 * @param message The message that should be appended to the 577 * additional log information for this operation. 578 */ 579 public final void appendAdditionalLogMessage(Message message) 580 { 581 if (additionalLogMessage == null) 582 { 583 additionalLogMessage = new MessageBuilder(message); 584 } 585 else 586 { 587 additionalLogMessage.append(message); 588 } 589 } 590 591 592 593 /** 594 * Retrieves the matched DN for this operation. 595 * 596 * @return The matched DN for this operation, or {@code null} if 597 * the operation has not yet completed or does not have a 598 * matched DN. 599 */ 600 public final DN getMatchedDN() 601 { 602 return matchedDN; 603 } 604 605 606 607 /** 608 * Specifies the matched DN for this operation. This may not be 609 * called by post-response plugins. 610 * 611 * @param matchedDN The matched DN for this operation. 612 */ 613 public final void setMatchedDN(DN matchedDN) 614 { 615 this.matchedDN = matchedDN; 616 } 617 618 619 620 /** 621 * Retrieves the set of referral URLs for this operation. Its 622 * contents must not be altered by the caller. 623 * 624 * @return The set of referral URLs for this operation, or 625 * {@code null} if the operation is not yet complete or 626 * does not have a set of referral URLs. 627 */ 628 public final List<String> getReferralURLs() 629 { 630 return referralURLs; 631 } 632 633 634 635 /** 636 * Specifies the set of referral URLs for this operation. This may 637 * not be called by post-response plugins. 638 * 639 * @param referralURLs The set of referral URLs for this 640 * operation. 641 */ 642 public final void setReferralURLs(List<String> referralURLs) 643 { 644 this.referralURLs = referralURLs; 645 } 646 647 648 649 /** 650 * Sets the response elements for this operation based on the 651 * information contained in the provided {@code DirectoryException} 652 * object. This method may not be called by post-response plugins. 653 * 654 * @param directoryException The exception containing the 655 * information to use for the response 656 * elements. 657 */ 658 public final void setResponseData( 659 DirectoryException directoryException) 660 { 661 this.resultCode = directoryException.getResultCode(); 662 this.matchedDN = directoryException.getMatchedDN(); 663 this.referralURLs = directoryException.getReferralURLs(); 664 665 appendErrorMessage(directoryException.getMessageObject()); 666 } 667 668 669 670 /** 671 * Indicates whether this is an internal operation rather than one 672 * that was requested by an external client. 673 * 674 * @return {@code true} if this is an internal operation, or 675 * {@code false} if it is not. 676 */ 677 public final boolean isInternalOperation() 678 { 679 return isInternalOperation; 680 } 681 682 683 684 /** 685 * Specifies whether this is an internal operation rather than one 686 * that was requested by an external client. This may not be called 687 * from within a plugin. 688 * 689 * @param isInternalOperation Specifies whether this is an 690 * internal operation rather than one 691 * that was requested by an external 692 * client. 693 */ 694 public final void setInternalOperation(boolean isInternalOperation) 695 { 696 this.isInternalOperation = isInternalOperation; 697 } 698 699 700 701 /** 702 * Indicates whether this is a synchronization operation rather than 703 * one that was requested by an external client. 704 * 705 * @return {@code true} if this is a data synchronization 706 * operation, or {@code false} if it is not. 707 */ 708 public final boolean isSynchronizationOperation() 709 { 710 return isSynchronizationOperation; 711 } 712 713 714 715 /** 716 * Specifies whether this is a synchronization operation rather than 717 * one that was requested by an external client. This method may 718 * not be called from within a plugin. 719 * 720 * @param isSynchronizationOperation Specifies whether this is a 721 * synchronization operation 722 * rather than one that was 723 * requested by an external 724 * client. 725 */ 726 public final void setSynchronizationOperation( 727 boolean isSynchronizationOperation) 728 { 729 this.isSynchronizationOperation = isSynchronizationOperation; 730 } 731 732 733 734 /** 735 * Indicates whether this operation needs to be synchronized to 736 * other copies of the data. 737 * 738 * @return {@code true} if this operation should not be 739 * synchronized, or {@code false} if it should be 740 * synchronized. 741 */ 742 public boolean dontSynchronize() 743 { 744 return dontSynchronizeFlag; 745 } 746 747 748 749 /** 750 * Specifies whether this operation must be synchronized to other 751 * copies of the data. 752 * 753 * @param dontSynchronize Specifies whether this operation must be 754 * synchronized to other copies 755 * of the data. 756 */ 757 public final void setDontSynchronize(boolean dontSynchronize) 758 { 759 this.dontSynchronizeFlag = dontSynchronize; 760 } 761 762 763 764 /** 765 * Retrieves the entry for the user that should be considered the 766 * authorization identity for this operation. In many cases, it 767 * will be the same as the authorization entry for the underlying 768 * client connection, or {@code null} if no authentication has been 769 * performed on that connection. However, it may be some other 770 * value if special processing has been requested (e.g., the 771 * operation included a proxied authorization control). This method 772 * should not be called by pre-parse plugins because the correct 773 * value may not yet have been determined. 774 * 775 * @return The entry for the user that should be considered the 776 * authorization identity for this operation, or 777 * {@code null} if the authorization identity should be the 778 * unauthenticated user. 779 */ 780 public final Entry getAuthorizationEntry() 781 { 782 return authorizationEntry; 783 } 784 785 786 787 /** 788 * Provides the entry for the user that should be considered the 789 * authorization identity for this operation. This must not be 790 * called from within a plugin. 791 * 792 * @param authorizationEntry The entry for the user that should be 793 * considered the authorization identity 794 * for this operation, or {@code null} 795 * if it should be the unauthenticated 796 * user. 797 */ 798 public final void setAuthorizationEntry(Entry authorizationEntry) 799 { 800 this.authorizationEntry = authorizationEntry; 801 } 802 803 804 805 /** 806 * Retrieves the authorization DN for this operation. In many 807 * cases, it will be the same as the DN of the authenticated user 808 * for the underlying connection, or the null DN if no 809 * authentication has been performed on that connection. However, 810 * it may be some other value if special processing has been 811 * requested (e.g., the operation included a proxied authorization 812 * control). This method should not be called by pre-parse plugins 813 * because the correct value may not have yet been determined. 814 * 815 * @return The authorization DN for this operation, or the null DN 816 * if it should be the unauthenticated user.. 817 */ 818 public final DN getAuthorizationDN() 819 { 820 if (authorizationEntry == null) 821 { 822 return DN.nullDN(); 823 } 824 else 825 { 826 return authorizationEntry.getDN(); 827 } 828 } 829 830 831 832 /** 833 * Retrieves the set of attachments defined for this operation, as a 834 * mapping between the attachment name and the associated object. 835 * 836 * @return The set of attachments defined for this operation. 837 */ 838 public final Map<String,Object> getAttachments() 839 { 840 return attachments; 841 } 842 843 844 845 /** 846 * Set the attachments to the operation. 847 * 848 * @param attachments - Attachments to register within the 849 * operation 850 */ 851 public final void setAttachments(Map<String, Object> attachments) 852 { 853 this.attachments = attachments; 854 } 855 856 857 858 /** 859 * Retrieves the attachment with the specified name. 860 * 861 * @param name The name for the attachment to retrieve. It will 862 * be treated in a case-sensitive manner. 863 * 864 * @return The requested attachment object, or {@code null} if it 865 * does not exist. 866 */ 867 public final Object getAttachment(String name) 868 { 869 return attachments.get(name); 870 } 871 872 873 874 /** 875 * Removes the attachment with the specified name. 876 * 877 * @param name The name for the attachment to remove. It will be 878 * treated in a case-sensitive manner. 879 * 880 * @return The attachment that was removed, or {@code null} if it 881 * does not exist. 882 */ 883 public final Object removeAttachment(String name) 884 { 885 return attachments.remove(name); 886 } 887 888 889 890 /** 891 * Sets the value of the specified attachment. If an attachment 892 * already exists with the same name, it will be replaced. 893 * Otherwise, a new attachment will be added. 894 * 895 * @param name The name to use for the attachment. 896 * @param value The value to use for the attachment. 897 * 898 * @return The former value held by the attachment with the given 899 * name, or {@code null} if there was previously no such 900 * attachment. 901 */ 902 public final Object setAttachment(String name, Object value) 903 { 904 return attachments.put(name, value); 905 } 906 907 908 909 /** 910 * Indicates that processing on this operation has completed 911 * successfully and that the client should perform any associated 912 * cleanup work. 913 */ 914 public final void operationCompleted() 915 { 916 // Notify the client connection that this operation is complete 917 // and that it no longer needs to be retained. 918 clientConnection.removeOperationInProgress(messageID); 919 } 920 921 922 923 /** 924 * Attempts to cancel this operation before processing has 925 * completed. 926 * 927 * @param cancelRequest Information about the way in which the 928 * operation should be canceled. 929 * 930 * @return A code providing information on the result of the 931 * cancellation. 932 */ 933 public CancelResult cancel(CancelRequest cancelRequest) 934 { 935 abort(cancelRequest); 936 937 long stopWaitingTime = System.currentTimeMillis() + 5000; 938 while ((cancelResult == null) && 939 (System.currentTimeMillis() < stopWaitingTime)) 940 { 941 try 942 { 943 Thread.sleep(50); 944 } 945 catch (Exception e) 946 { 947 if (debugEnabled()) 948 { 949 TRACER.debugCaught(DebugLogLevel.ERROR, e); 950 } 951 } 952 } 953 954 if (cancelResult == null) 955 { 956 // This can happen in some rare cases (e.g., if a client 957 // disconnects and there is still a lot of data to send to 958 // that client), and in this case we'll prevent the cancel 959 // thread from blocking for a long period of time. 960 cancelResult = new CancelResult(ResultCode.CANNOT_CANCEL, null); 961 } 962 963 return cancelResult; 964 } 965 966 967 968 /** 969 * Attempts to cancel this operation before processing has 970 * completed without waiting for a cancel result. 971 * 972 * @param cancelRequest Information about the way in which the 973 * operation should be canceled. 974 */ 975 public synchronized void abort(CancelRequest cancelRequest) 976 { 977 if(cancelResult == null && this.cancelRequest == null) 978 { 979 this.cancelRequest = cancelRequest; 980 } 981 } 982 983 984 985 /** 986 * {@inheritDoc} 987 */ 988 public synchronized final void 989 checkIfCanceled(boolean signalTooLate) 990 throws CanceledOperationException { 991 if(cancelRequest != null) 992 { 993 throw new CanceledOperationException(cancelRequest); 994 } 995 996 if(signalTooLate && cancelResult != null) 997 { 998 cancelResult = new CancelResult(ResultCode.TOO_LATE, null); 999 } 1000 } 1001 1002 1003 1004 /** 1005 * {@inheritDoc} 1006 */ 1007 public final CancelRequest getCancelRequest() 1008 { 1009 return cancelRequest; 1010 } 1011 1012 /** 1013 * {@inheritDoc} 1014 */ 1015 public final CancelResult getCancelResult() 1016 { 1017 return cancelResult; 1018 } 1019 1020 1021 1022 /** 1023 * Retrieves a string representation of this operation. 1024 * 1025 * @return A string representation of this operation. 1026 */ 1027 public final String toString() 1028 { 1029 StringBuilder buffer = new StringBuilder(); 1030 toString(buffer); 1031 return buffer.toString(); 1032 } 1033 1034 1035 1036 /** 1037 * Appends a string representation of this operation to the provided 1038 * buffer. 1039 * 1040 * @param buffer The buffer into which a string representation of 1041 * this operation should be appended. 1042 */ 1043 public abstract void toString(StringBuilder buffer); 1044 1045 1046 1047 /** 1048 * Retrieves the time that processing started for this operation. 1049 * 1050 * @return The time that processing started for this operation. 1051 */ 1052 public final long getProcessingStartTime() 1053 { 1054 return processingStartTime; 1055 } 1056 1057 1058 1059 /** 1060 * Set the time at which the processing started for this operation. 1061 */ 1062 public final void setProcessingStartTime() 1063 { 1064 processingStartTime = System.currentTimeMillis(); 1065 if(useNanoTime) 1066 { 1067 processingStartNanoTime = System.nanoTime(); 1068 } 1069 } 1070 1071 1072 1073 /** 1074 * Retrieves the time that processing stopped for this operation. 1075 * This will actually hold a time immediately before the response 1076 * was sent to the client. 1077 * 1078 * @return The time that processing stopped for this operation. 1079 */ 1080 public final long getProcessingStopTime() 1081 { 1082 return processingStopTime; 1083 } 1084 1085 1086 1087 /** 1088 * Set the time at which the processing stopped for this operation. 1089 * This will actually hold a time immediately before the response 1090 * was sent to the client. 1091 */ 1092 public final void setProcessingStopTime() 1093 { 1094 this.processingStopTime = System.currentTimeMillis(); 1095 if(useNanoTime) 1096 { 1097 this.processingStopNanoTime = System.nanoTime(); 1098 } 1099 } 1100 1101 1102 1103 /** 1104 * Retrieves the length of time in milliseconds that 1105 * the server spent processing this operation. This should not be 1106 * called until after the server has sent the response to the 1107 * client. 1108 * 1109 * @return The length of time in milliseconds that 1110 * the server spent processing this operation. 1111 */ 1112 public final long getProcessingTime() 1113 { 1114 return (processingStopTime - processingStartTime); 1115 } 1116 1117 1118 1119 /** 1120 * Retrieves the length of time in nanoseconds that 1121 * the server spent processing this operation if available. 1122 * This should not be called until after the server has sent the 1123 * response to the client. 1124 * 1125 * @return The length of time in nanoseconds that the server 1126 * spent processing this operation or -1 if its not 1127 * available. 1128 */ 1129 public final long getProcessingNanoTime() 1130 { 1131 if(useNanoTime) 1132 { 1133 return (processingStopNanoTime - processingStartNanoTime); 1134 } 1135 else 1136 { 1137 return -1; 1138 } 1139 } 1140 1141 1142 1143 /** 1144 * Performs the work of actually processing this operation. This 1145 * should include all processing for the operation, including 1146 * invoking pre-parse and post-response plugins, logging messages 1147 * and any other work that might need to be done in the course of 1148 * processing. 1149 */ 1150 public abstract void run(); 1151 } 1152