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