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 legal-notices/CDDLv1_0.txt 010 * or http://forgerock.org/license/CDDLv1.0.html. 011 * See the License for the specific language governing permissions 012 * and limitations under the License. 013 * 014 * When distributing Covered Code, include this CDDL HEADER in each 015 * file and include the License file at legal-notices/CDDLv1_0.txt. 016 * If applicable, add the following below this CDDL HEADER, with the 017 * fields enclosed by brackets "[]" replaced with your own identifying 018 * information: 019 * Portions Copyright [yyyy] [name of copyright owner] 020 * 021 * CDDL HEADER END 022 * 023 * 024 * Copyright 2007-2008 Sun Microsystems, Inc. 025 * Portions Copyright 2013-2015 ForgeRock AS 026 */ 027package org.opends.server.core; 028 029import static org.opends.messages.CoreMessages.*; 030import static org.opends.server.core.DirectoryServer.*; 031import static org.opends.server.loggers.AccessLogger.*; 032 033import java.util.List; 034 035import org.forgerock.i18n.LocalizableMessage; 036import org.forgerock.opendj.ldap.ResultCode; 037import org.opends.server.api.ClientConnection; 038import org.opends.server.types.*; 039import org.opends.server.types.operation.PostOperationAbandonOperation; 040import org.opends.server.types.operation.PreParseAbandonOperation; 041 042/** 043 * This class defines an operation that may be used to abandon an operation 044 * that may already be in progress in the Directory Server. 045 */ 046public class AbandonOperationBasis extends AbstractOperation 047 implements AbandonOperation, 048 PreParseAbandonOperation, 049 PostOperationAbandonOperation 050{ 051 052 /** The message ID of the operation that should be abandoned. */ 053 private final int idToAbandon; 054 055 056 /** 057 * Creates a new abandon operation with the provided information. 058 * 059 * @param clientConnection The client connection with which this operation 060 * is associated. 061 * @param operationID The operation ID for this operation. 062 * @param messageID The message ID of the request with which this 063 * operation is associated. 064 * @param requestControls The set of controls included in the request. 065 * @param idToAbandon The message ID of the operation that should be 066 * abandoned. 067 */ 068 public AbandonOperationBasis( 069 ClientConnection clientConnection, 070 long operationID, 071 int messageID, 072 List<Control> requestControls, 073 int idToAbandon) 074 { 075 super(clientConnection, operationID, messageID, requestControls); 076 077 078 this.idToAbandon = idToAbandon; 079 this.cancelResult = new CancelResult(ResultCode.CANNOT_CANCEL, 080 ERR_CANNOT_CANCEL_ABANDON.get()); 081 } 082 083 084 085 /** 086 * Retrieves the message ID of the operation that should be abandoned. 087 * 088 * @return The message ID of the operation that should be abandoned. 089 */ 090 @Override 091 public final int getIDToAbandon() 092 { 093 return idToAbandon; 094 } 095 096 097 098 /** {@inheritDoc} */ 099 @Override 100 public DN getProxiedAuthorizationDN() 101 { 102 return null; 103 } 104 105 106 107 /** {@inheritDoc} */ 108 @Override 109 public void setProxiedAuthorizationDN(DN proxiedAuthorizationDN) 110 { 111 } 112 113 114 115 /** {@inheritDoc} */ 116 @Override 117 public final OperationType getOperationType() 118 { 119 // Note that no debugging will be done in this method because it is a likely 120 // candidate for being called by the logging subsystem. 121 122 return OperationType.ABANDON; 123 } 124 125 126 127 /** {@inheritDoc} */ 128 @Override 129 public final List<Control> getResponseControls() 130 { 131 // An abandon operation can never have a response, so just return an empty 132 // list. 133 return NO_RESPONSE_CONTROLS; 134 } 135 136 137 138 /** {@inheritDoc} */ 139 @Override 140 public final void addResponseControl(Control control) 141 { 142 // An abandon operation can never have a response, so just ignore this. 143 } 144 145 146 147 /** {@inheritDoc} */ 148 @Override 149 public final void removeResponseControl(Control control) 150 { 151 // An abandon operation can never have a response, so just ignore this. 152 } 153 154 155 156 /** 157 * Performs the work of actually processing this operation. This 158 * should include all processing for the operation, including 159 * invoking plugins, logging messages, performing access control, 160 * managing synchronization, and any other work that might need to 161 * be done in the course of processing. 162 */ 163 @Override 164 public final void run() 165 { 166 setResultCode(ResultCode.UNDEFINED); 167 168 // Start the processing timer. 169 setProcessingStartTime(); 170 171 logAbandonRequest(this); 172 173 // Create a labeled block of code that we can break out of if a problem is detected. 174abandonProcessing: 175 { 176 // Invoke the pre-parse abandon plugins. 177 if (!processOperationResult(getPluginConfigManager().invokePreParseAbandonPlugins(this))) 178 { 179 break abandonProcessing; 180 } 181 182 // Actually perform the abandon operation. Make sure to set the result 183 // code to reflect whether the abandon was successful and an error message 184 // if it was not. Even though there is no response, the result should 185 // still be logged. 186 // 187 // Even though it is technically illegal to send a response for 188 // operations that have been abandoned, it may be a good idea to do so 189 // to ensure that the requestor isn't left hanging. This will be a 190 // configurable option in the server. 191 boolean notifyRequestor = DirectoryServer.notifyAbandonedOperations(); 192 193 LocalizableMessage cancelReason = INFO_CANCELED_BY_ABANDON_REQUEST.get(messageID); 194 195 CancelRequest _cancelRequest = new CancelRequest(notifyRequestor, 196 cancelReason); 197 198 CancelResult result = clientConnection.cancelOperation(idToAbandon, 199 _cancelRequest); 200 201 setResultCode(result.getResultCode()); 202 appendErrorMessage(result.getResponseMessage()); 203 204 if (!processOperationResult(getPluginConfigManager().invokePostOperationAbandonPlugins(this))) 205 { 206 break abandonProcessing; 207 } 208 } 209 210 211 // Stop the processing timer. 212 setProcessingStopTime(); 213 214 215 // Log the result of the abandon operation. 216 logAbandonResult(this); 217 } 218 219 220 221 /** {@inheritDoc} */ 222 @Override 223 public final void toString(StringBuilder buffer) 224 { 225 buffer.append("AbandonOperation(connID="); 226 buffer.append(clientConnection.getConnectionID()); 227 buffer.append(", opID="); 228 buffer.append(operationID); 229 buffer.append(", idToAbandon="); 230 buffer.append(idToAbandon); 231 buffer.append(")"); 232 } 233}