001/* 002 * Copyright 2007-2014 UnboundID Corp. 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2008-2014 UnboundID Corp. 007 * 008 * This program is free software; you can redistribute it and/or modify 009 * it under the terms of the GNU General Public License (GPLv2 only) 010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 011 * as published by the Free Software Foundation. 012 * 013 * This program is distributed in the hope that it will be useful, 014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 016 * GNU General Public License for more details. 017 * 018 * You should have received a copy of the GNU General Public License 019 * along with this program; if not, see <http://www.gnu.org/licenses>. 020 */ 021package com.unboundid.ldap.sdk.controls; 022 023 024 025import com.unboundid.ldap.sdk.Control; 026import com.unboundid.ldap.sdk.LDAPException; 027import com.unboundid.ldap.sdk.ResultCode; 028import com.unboundid.util.NotMutable; 029import com.unboundid.util.ThreadSafety; 030import com.unboundid.util.ThreadSafetyLevel; 031 032import static com.unboundid.ldap.sdk.controls.ControlMessages.*; 033 034 035 036/** 037 * This class provides an implementation of the subtree delete request control 038 * as defined in draft-armijo-ldap-treedelete. This can be used to delete an 039 * entry and all subordinate entries in a single operation. 040 * <BR><BR> 041 * Normally, if an entry has one or more subordinates, a directory server will 042 * refuse to delete it by rejecting the request with a 043 * {@link ResultCode#NOT_ALLOWED_ON_NONLEAF} result. In such cases, it is 044 * necessary to first recursively remove all of its subordinates before the 045 * target entry can be deleted. However, this subtree delete request control 046 * can be used to request that the server remove the entry and all subordinates 047 * as a single operation. For servers that support this control, it is 048 * generally much more efficient and convenient than removing all of the 049 * subordinate entries one at a time. 050 * <BR><BR> 051 * <H2>Example</H2> 052 * The following example demonstrates the use of the subtree delete control: 053 * <PRE> 054 * // First, try to delete an entry that has children, but don't include the 055 * // subtree delete control. This delete attempt should fail, and the 056 * // "NOT_ALLOWED_ON_NONLEAF" result is most appropriate if the failure reason 057 * // is that the entry has subordinates. 058 * DeleteRequest deleteRequest = 059 * new DeleteRequest("ou=entry with children,dc=example,dc=com"); 060 * LDAPResult resultWithoutControl; 061 * try 062 * { 063 * resultWithoutControl = connection.delete(deleteRequest); 064 * // We shouldn't get here because the delete should fail. 065 * } 066 * catch (LDAPException le) 067 * { 068 * // This is expected because the entry has children. 069 * resultWithoutControl = le.toLDAPResult(); 070 * ResultCode resultCode = le.getResultCode(); 071 * String errorMessageFromServer = le.getDiagnosticMessage(); 072 * } 073 * LDAPTestUtils.assertResultCodeEquals(resultWithoutControl, 074 * ResultCode.NOT_ALLOWED_ON_NONLEAF); 075 * 076 * // Update the delete request to include the subtree delete request control 077 * // and try again. 078 * deleteRequest.addControl(new SubtreeDeleteRequestControl()); 079 * LDAPResult resultWithControl; 080 * try 081 * { 082 * resultWithControl = connection.delete(deleteRequest); 083 * // The delete should no longer be rejected just because the target entry 084 * // has children. 085 * } 086 * catch (LDAPException le) 087 * { 088 * // The delete still failed for some other reason. 089 * resultWithControl = le.toLDAPResult(); 090 * ResultCode resultCode = le.getResultCode(); 091 * String errorMessageFromServer = le.getDiagnosticMessage(); 092 * } 093 * LDAPTestUtils.assertResultCodeEquals(resultWithControl, ResultCode.SUCCESS); 094 * </PRE> 095 */ 096@NotMutable() 097@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 098public final class SubtreeDeleteRequestControl 099 extends Control 100{ 101 /** 102 * The OID (1.2.840.113556.1.4.805) for the subtree delete request control. 103 */ 104 public static final String SUBTREE_DELETE_REQUEST_OID = 105 "1.2.840.113556.1.4.805"; 106 107 108 109 /** 110 * The serial version UID for this serializable class. 111 */ 112 private static final long serialVersionUID = 3748121547717081961L; 113 114 115 116 /** 117 * Creates a new subtree delete request control. The control will not be 118 * marked critical. 119 */ 120 public SubtreeDeleteRequestControl() 121 { 122 super(SUBTREE_DELETE_REQUEST_OID, false, null); 123 } 124 125 126 127 /** 128 * Creates a new subtree delete request control. 129 * 130 * @param isCritical Indicates whether the control should be marked 131 * critical. 132 */ 133 public SubtreeDeleteRequestControl(final boolean isCritical) 134 { 135 super(SUBTREE_DELETE_REQUEST_OID, isCritical, null); 136 } 137 138 139 140 /** 141 * Creates a new subtree delete request control which is decoded from the 142 * provided generic control. 143 * 144 * @param control The generic control to be decoded as a subtree delete 145 * request control. 146 * 147 * @throws LDAPException If the provided control cannot be decoded as a 148 * subtree delete request control. 149 */ 150 public SubtreeDeleteRequestControl(final Control control) 151 throws LDAPException 152 { 153 super(control); 154 155 if (control.hasValue()) 156 { 157 throw new LDAPException(ResultCode.DECODING_ERROR, 158 ERR_SUBTREE_DELETE_HAS_VALUE.get()); 159 } 160 } 161 162 163 164 /** 165 * {@inheritDoc} 166 */ 167 @Override() 168 public String getControlName() 169 { 170 return INFO_CONTROL_NAME_SUBTREE_DELETE_REQUEST.get(); 171 } 172 173 174 175 /** 176 * {@inheritDoc} 177 */ 178 @Override() 179 public void toString(final StringBuilder buffer) 180 { 181 buffer.append("SubtreeDeleteRequestControl(isCritical="); 182 buffer.append(isCritical()); 183 buffer.append(')'); 184 } 185}