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