001/* 002 * Copyright 2019-2024 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright 2019-2024 Ping Identity Corporation 007 * 008 * Licensed under the Apache License, Version 2.0 (the "License"); 009 * you may not use this file except in compliance with the License. 010 * You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, software 015 * distributed under the License is distributed on an "AS IS" BASIS, 016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 017 * See the License for the specific language governing permissions and 018 * limitations under the License. 019 */ 020/* 021 * Copyright (C) 2019-2024 Ping Identity Corporation 022 * 023 * This program is free software; you can redistribute it and/or modify 024 * it under the terms of the GNU General Public License (GPLv2 only) 025 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 026 * as published by the Free Software Foundation. 027 * 028 * This program is distributed in the hope that it will be useful, 029 * but WITHOUT ANY WARRANTY; without even the implied warranty of 030 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 031 * GNU General Public License for more details. 032 * 033 * You should have received a copy of the GNU General Public License 034 * along with this program; if not, see <http://www.gnu.org/licenses>. 035 */ 036package com.unboundid.util; 037 038 039 040import java.io.Serializable; 041import java.util.Collections; 042import java.util.SortedMap; 043import java.util.TreeMap; 044 045import com.unboundid.ldap.sdk.DN; 046import com.unboundid.ldap.sdk.LDAPResult; 047import com.unboundid.ldap.sdk.SearchResult; 048 049 050 051/** 052 * This class provides a data structure with information about the results of 053 * a subtree delete attempt. 054 * 055 * @see SubtreeDeleter 056 */ 057@NotMutable() 058@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 059public final class SubtreeDeleterResult 060 implements Serializable 061{ 062 /** 063 * The serial version UID for this serializable class. 064 */ 065 private static final long serialVersionUID = -4801520019525316763L; 066 067 068 069 // Indicates whether the target subtree is inaccessible. 070 private final boolean subtreeInaccessible; 071 072 // An error that occurred during an attempt to make the target subtree 073 // inaccessible. 074 @Nullable private final LDAPResult setSubtreeAccessibilityError; 075 076 // The number of entries that were successfully deleted. 077 private final long entriesDeleted; 078 079 // An error that occurred during search processing that prevented identifying 080 // all of the entries in the target subtree. 081 @Nullable private final SearchResult searchError; 082 083 // A map that contains the DNs of the entries that could not be deleted, 084 // associated with a result indicating the reason for the delete failure. 085 // It will be sorted in descending order 086 @NotNull private final TreeMap<DN,LDAPResult> deleteErrors; 087 088 089 090 /** 091 * Creates a new subtree deleter result with the provided information. 092 * 093 * @param setSubtreeAccessibilityError 094 * An {@code LDAPResult} object with information about an error 095 * that occurred while trying to make the target subtree 096 * inaccessible, or while trying to remove that accessibility 097 * restriction after all other processing completed successfully 098 * (and the two cases can be differentiated using the value of 099 * the {@code subtreeInaccessible} argument). This may be 100 * {@code null} if no attempt was made to alter the accessibility 101 * of the target subtree, or if its accessibility was 102 * successfully altered. 103 * @param subtreeInaccessible 104 * Indicates whether the target subtree was left inaccessible 105 * after processing completed. If the subtree was made 106 * inaccessible, it will be left in an inaccessible state if any 107 * error occurs during search or delete processing. The 108 * accessibility restriction will be removed if all processing 109 * completes successfully. 110 * @param searchError 111 * A search result with information about an error that occurred 112 * during search processing that prevented identifying all of the 113 * entries in the target subtree. It may be {@code null} if 114 * there was no error during search processing. 115 * @param entriesDeleted 116 * The number of entries that were successfully deleted. 117 * @param deleteErrors 118 * A map that contains the DNs of entries that could not be 119 * deleted, associated with a result indicating the reason for 120 * the delete failure. It must not be {@code null} but may be 121 * empty. 122 */ 123 SubtreeDeleterResult(@Nullable final LDAPResult setSubtreeAccessibilityError, 124 final boolean subtreeInaccessible, 125 @Nullable final SearchResult searchError, 126 final long entriesDeleted, 127 @NotNull final TreeMap<DN,LDAPResult> deleteErrors) 128 { 129 this.setSubtreeAccessibilityError = setSubtreeAccessibilityError; 130 this.subtreeInaccessible = subtreeInaccessible; 131 this.searchError = searchError; 132 this.entriesDeleted = entriesDeleted; 133 this.deleteErrors = deleteErrors; 134 } 135 136 137 138 /** 139 * Indicates whether the {@link SubtreeDeleter} processing was completely 140 * successful. 141 * 142 * @return {@code true} if the subtree deleter processing was completely 143 * successful, or {@code false} if not. 144 */ 145 public boolean completelySuccessful() 146 { 147 return ((setSubtreeAccessibilityError == null) && 148 (! subtreeInaccessible) && 149 (searchError == null) && 150 deleteErrors.isEmpty()); 151 } 152 153 154 155 /** 156 * Retrieves an {@code LDAPResult} that provides information about an error 157 * that occurred while trying to make the target subtree inaccessible before 158 * subtree delete processing, or if an error occurred while trying to remove 159 * the subtree accessibility restriction after all other processing had 160 * completed successfully. This may be {@code null} if no attempts was made 161 * to alter the subtree accessibility, or if no error occurred during 162 * processing. 163 * <BR><BR> 164 * If the return value is non-{@code null} and {@link #subtreeInaccessible} 165 * returns {@code false}, then the error occurred while attempting to make the 166 * target subtree inaccessible. If the return value is non-{@code null} and 167 * {@code isSubtreeInaccessible} returns {@code true}, then the error occurred 168 * while attempting to remove the subtree accessibility restriction. 169 * 170 * @return An {@code LDAPResult} that provides information about an error 171 * that occurred while attempting to alter the accessibility of the 172 * target subtree, or {@code null} if no such error occurred. 173 */ 174 @Nullable() 175 public LDAPResult getSetSubtreeAccessibilityError() 176 { 177 return setSubtreeAccessibilityError; 178 } 179 180 181 182 /** 183 * Indicates whether the target subtree was left in an inaccessible state 184 * after some error occurred during subtree delete processing. 185 * 186 * @return {@code true} if the subtree was set inaccessible at the start of 187 * subtree delete processing and remains inaccessible after an error 188 * occurred during processing, or {@code false} if the subtree 189 * accessibility was not altered or if the accessibility restriction 190 * was removed after all processing completed successfully. 191 */ 192 public boolean subtreeInaccessible() 193 { 194 return subtreeInaccessible; 195 } 196 197 198 199 /** 200 * Retrieves a search result with information about an error that occurred 201 * during search processing that prevented identifying all of the entries in 202 * the target subtree. 203 * 204 * @return A search result with information about an error that occurred 205 * during search processing that prevented identifying all of the 206 * entries in the target subtree, or {@code null} if no error 207 * occurred during search processing. 208 */ 209 @Nullable() 210 public SearchResult getSearchError() 211 { 212 return searchError; 213 } 214 215 216 217 /** 218 * Retrieves the number of entries that were successfully deleted. 219 * 220 * @return The number of entries that were successfully deleted. 221 */ 222 public long getEntriesDeleted() 223 { 224 return entriesDeleted; 225 } 226 227 228 229 /** 230 * Retrieves an unmodifiable sorted map of the DNs of entries that could not 231 * be successfully deleted, each of which is associated with an 232 * {@code LDAPResult} indicating the reason for the delete failure. The map 233 * will be ordered in ascending order using the comparator provided by the 234 * {@code DN} class (that is, with ancestor entries before their descendants). 235 * 236 * @return An unmodifiable sorted map of the DNs of the entries that could 237 * not be deleted, each of which is associated with an 238 * {@code LDAPResult} indicating the reason for the delete failure. 239 */ 240 @NotNull() 241 public SortedMap<DN,LDAPResult> getDeleteErrors() 242 { 243 return Collections.unmodifiableSortedMap(deleteErrors); 244 } 245 246 247 248 /** 249 * Retrieves an unmodifiable sorted map of the DNs of entries that could not 250 * be successfully deleted, each of which is associated with an 251 * {@code LDAPResult} indicating the reason for the delete failure. The map 252 * will be ordered in descending order using the comparator provided by the 253 * {@code DN} class (that is, with descendant entries before their ancestors). 254 * 255 * @return An unmodifiable sorted map of the DNs of the entries that could 256 * not be deleted, each of which is associated with an 257 * {@code LDAPResult} indicating the reason for the delete failure. 258 */ 259 @NotNull() 260 public SortedMap<DN,LDAPResult> getDeleteErrorsDescendingMap() 261 { 262 return Collections.unmodifiableSortedMap(deleteErrors.descendingMap()); 263 } 264 265 266 267 /** 268 * Retrieves the delete errors as a {@code TreeMap}. 269 * 270 * @return Retrieves the delete errors as a {@code TreeMap}. 271 */ 272 @NotNull() 273 TreeMap<DN,LDAPResult> getDeleteErrorsTreeMap() 274 { 275 return deleteErrors; 276 } 277 278 279 280 /** 281 * Retrieves a string representation of this subtree deleter result. 282 * 283 * @return A string representation of this subtree deleter result. 284 */ 285 @Override() 286 @NotNull() 287 public String toString() 288 { 289 final StringBuilder buffer = new StringBuilder(); 290 toString(buffer); 291 return buffer.toString(); 292 } 293 294 295 296 /** 297 * Appends a string representation of this subtree deleter result to the 298 * provided buffer. 299 * 300 * @param buffer The buffer to which the string representation should be 301 * appended. 302 */ 303 public void toString(@NotNull final StringBuilder buffer) 304 { 305 buffer.append("SubtreeDeleterResult=(completelySuccessful="); 306 buffer.append(completelySuccessful()); 307 308 if (setSubtreeAccessibilityError != null) 309 { 310 buffer.append(", setSubtreeAccessibilityError="); 311 setSubtreeAccessibilityError.toString(buffer); 312 } 313 314 if (subtreeInaccessible) 315 { 316 buffer.append(", subtreeInaccessible=true"); 317 } 318 319 if (searchError != null) 320 { 321 buffer.append(", searchError="); 322 searchError.toString(buffer); 323 } 324 325 buffer.append(", entriesDeleted="); 326 buffer.append(entriesDeleted); 327 328 if (! deleteErrors.isEmpty()) 329 { 330 buffer.append(", deleteErrors="); 331 buffer.append(deleteErrors); 332 } 333 } 334}