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-2010 Sun Microsystems, Inc. 025 * Portions Copyright 2013-2015 ForgeRock AS 026 */ 027package org.opends.server.core; 028 029import java.util.ArrayList; 030import java.util.List; 031 032import org.forgerock.i18n.slf4j.LocalizedLogger; 033import org.forgerock.opendj.ldap.ByteString; 034import org.forgerock.opendj.ldap.ResultCode; 035import org.opends.server.api.ClientConnection; 036import org.opends.server.types.*; 037import org.opends.server.types.operation.PostResponseDeleteOperation; 038import org.opends.server.types.operation.PreParseDeleteOperation; 039import org.opends.server.workflowelement.localbackend.LocalBackendDeleteOperation; 040 041import static org.opends.messages.CoreMessages.*; 042import static org.opends.server.core.DirectoryServer.*; 043import static org.opends.server.loggers.AccessLogger.*; 044import static org.opends.server.workflowelement.localbackend.LocalBackendWorkflowElement.*; 045 046/** 047 * This class defines an operation that may be used to remove an entry from the 048 * Directory Server. 049 */ 050public class DeleteOperationBasis 051 extends AbstractOperation 052 implements PreParseDeleteOperation, 053 DeleteOperation, 054 PostResponseDeleteOperation 055{ 056 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 057 058 /** The raw, unprocessed entry DN as included in the client request. */ 059 private ByteString rawEntryDN; 060 /** The DN of the entry for the delete operation. */ 061 private DN entryDN; 062 /** The proxied authorization target DN for this operation. */ 063 private DN proxiedAuthorizationDN; 064 /** The set of response controls for this delete operation. */ 065 private final List<Control> responseControls = new ArrayList<>(); 066 067 /** 068 * Creates a new delete operation with the provided information. 069 * 070 * @param clientConnection The client connection with which this operation 071 * is associated. 072 * @param operationID The operation ID for this operation. 073 * @param messageID The message ID of the request with which this 074 * operation is associated. 075 * @param requestControls The set of controls included in the request. 076 * @param rawEntryDN The raw, unprocessed DN of the entry to delete, 077 * as included in the client request. 078 */ 079 public DeleteOperationBasis(ClientConnection clientConnection, 080 long operationID, 081 int messageID, List<Control> requestControls, 082 ByteString rawEntryDN) 083 { 084 super(clientConnection, operationID, messageID, requestControls); 085 086 this.rawEntryDN = rawEntryDN; 087 } 088 089 090 091 /** 092 * Creates a new delete operation with the provided information. 093 * 094 * @param clientConnection The client connection with which this operation 095 * is associated. 096 * @param operationID The operation ID for this operation. 097 * @param messageID The message ID of the request with which this 098 * operation is associated. 099 * @param requestControls The set of controls included in the request. 100 * @param entryDN The entry DN for this delete operation. 101 */ 102 public DeleteOperationBasis(ClientConnection clientConnection, 103 long operationID, 104 int messageID, List<Control> requestControls, 105 DN entryDN) 106 { 107 super(clientConnection, operationID, messageID, requestControls); 108 109 this.entryDN = entryDN; 110 rawEntryDN = ByteString.valueOfUtf8(entryDN.toString()); 111 } 112 113 @Override 114 public final ByteString getRawEntryDN() 115 { 116 return rawEntryDN; 117 } 118 119 @Override 120 public final void setRawEntryDN(ByteString rawEntryDN) 121 { 122 this.rawEntryDN = rawEntryDN; 123 124 entryDN = null; 125 } 126 127 @Override 128 public final DN getEntryDN() 129 { 130 try 131 { 132 if (entryDN == null) 133 { 134 entryDN = DN.decode(rawEntryDN); 135 } 136 } 137 catch (DirectoryException de) 138 { 139 logger.traceException(de); 140 setResponseData(de); 141 } 142 return entryDN; 143 } 144 145 @Override 146 public final OperationType getOperationType() 147 { 148 // Note that no debugging will be done in this method because it is a likely 149 // candidate for being called by the logging subsystem. 150 return OperationType.DELETE; 151 } 152 153 @Override 154 public DN getProxiedAuthorizationDN() 155 { 156 return proxiedAuthorizationDN; 157 } 158 159 @Override 160 public final List<Control> getResponseControls() 161 { 162 return responseControls; 163 } 164 165 @Override 166 public final void addResponseControl(Control control) 167 { 168 responseControls.add(control); 169 } 170 171 @Override 172 public final void removeResponseControl(Control control) 173 { 174 responseControls.remove(control); 175 } 176 177 @Override 178 public final void toString(StringBuilder buffer) 179 { 180 buffer.append("DeleteOperation(connID="); 181 buffer.append(clientConnection.getConnectionID()); 182 buffer.append(", opID="); 183 buffer.append(operationID); 184 buffer.append(", dn="); 185 buffer.append(rawEntryDN); 186 buffer.append(")"); 187 } 188 189 @Override 190 public void setProxiedAuthorizationDN(DN proxiedAuthorizationDN) 191 { 192 this.proxiedAuthorizationDN = proxiedAuthorizationDN; 193 } 194 195 @Override 196 public final void run() 197 { 198 setResultCode(ResultCode.UNDEFINED); 199 200 // Start the processing timer. 201 setProcessingStartTime(); 202 203 logDeleteRequest(this); 204 205 // This flag is set to true as soon as a workflow has been executed. 206 boolean workflowExecuted = false; 207 try 208 { 209 // Invoke the pre-parse delete plugins. 210 if (!processOperationResult(getPluginConfigManager().invokePreParseDeletePlugins(this))) 211 { 212 return; 213 } 214 215 216 // Check for a request to cancel this operation. 217 checkIfCanceled(false); 218 219 220 // Process the entry DN to convert it from its raw form as provided by the 221 // client to the form required for the rest of the delete processing. 222 DN entryDN = getEntryDN(); 223 if (entryDN == null){ 224 return; 225 } 226 227 workflowExecuted = execute(this, entryDN); 228 } 229 catch(CanceledOperationException coe) 230 { 231 logger.traceException(coe); 232 233 setResultCode(ResultCode.CANCELLED); 234 cancelResult = new CancelResult(ResultCode.CANCELLED, null); 235 236 appendErrorMessage(coe.getCancelRequest().getCancelReason()); 237 } 238 finally 239 { 240 // Stop the processing timer. 241 setProcessingStopTime(); 242 243 // Log the delete response. 244 logDeleteResponse(this); 245 246 if(cancelRequest == null || cancelResult == null || 247 cancelResult.getResultCode() != ResultCode.CANCELLED || 248 cancelRequest.notifyOriginalRequestor() || 249 DirectoryServer.notifyAbandonedOperations()) 250 { 251 clientConnection.sendResponse(this); 252 } 253 254 255 // Invoke the post-response callbacks. 256 if (workflowExecuted) { 257 invokePostResponseCallbacks(); 258 } 259 260 // Invoke the post-response delete plugins. 261 invokePostResponsePlugins(workflowExecuted); 262 263 // If no cancel result, set it 264 if(cancelResult == null) 265 { 266 cancelResult = new CancelResult(ResultCode.TOO_LATE, null); 267 } 268 } 269 } 270 271 272 /** 273 * Invokes the post response plugins. If a workflow has been executed 274 * then invoke the post response plugins provided by the workflow 275 * elements of the workflow, otherwise invoke the post response plugins 276 * that have been registered with the current operation. 277 * 278 * @param workflowExecuted <code>true</code> if a workflow has been executed 279 */ 280 private void invokePostResponsePlugins(boolean workflowExecuted) 281 { 282 // Invoke the post response plugins 283 if (workflowExecuted) 284 { 285 // Invoke the post response plugins that have been registered by 286 // the workflow elements 287 List<LocalBackendDeleteOperation> localOperations = 288 (List)getAttachment(Operation.LOCALBACKENDOPERATIONS); 289 290 if (localOperations != null) 291 { 292 for (LocalBackendDeleteOperation localOperation : localOperations) 293 { 294 getPluginConfigManager().invokePostResponseDeletePlugins(localOperation); 295 } 296 } 297 } 298 else 299 { 300 // Invoke the post response plugins that have been registered with 301 // the current operation 302 getPluginConfigManager().invokePostResponseDeletePlugins(this); 303 } 304 } 305 306 @Override 307 public void updateOperationErrMsgAndResCode() 308 { 309 setResultCode(ResultCode.NO_SUCH_OBJECT); 310 appendErrorMessage(ERR_DELETE_NO_SUCH_ENTRY.get(getEntryDN())); 311 } 312 313 /** 314 * {@inheritDoc} 315 * 316 * This method always returns null. 317 */ 318 @Override 319 public Entry getEntryToDelete() { 320 return null; 321 } 322}