001/* 002 * Copyright 2007-2024 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright 2007-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) 2007-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.ldif; 037 038 039 040import java.util.ArrayList; 041import java.util.Arrays; 042import java.util.Collections; 043import java.util.List; 044 045import com.unboundid.ldap.sdk.Version; 046import com.unboundid.util.Debug; 047import com.unboundid.util.LDAPSDKException; 048import com.unboundid.util.NotMutable; 049import com.unboundid.util.NotNull; 050import com.unboundid.util.Nullable; 051import com.unboundid.util.StaticUtils; 052import com.unboundid.util.ThreadSafety; 053import com.unboundid.util.ThreadSafetyLevel; 054import com.unboundid.util.Validator; 055 056 057 058/** 059 * This class defines an exception that may be thrown if a problem occurs while 060 * attempting to decode data read from an LDIF source. It has a flag to 061 * indicate whether it is possible to try to continue reading additional 062 * information from the LDIF source, and also the approximate line number on 063 * which the problem was encountered. 064 */ 065@NotMutable() 066@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 067public final class LDIFException 068 extends LDAPSDKException 069{ 070 /** 071 * The serial version UID for this serializable class. 072 */ 073 private static final long serialVersionUID = 1665883395956836732L; 074 075 076 077 // Indicates whether it is possible to continue attempting to read from the 078 // LDIF source. 079 private final boolean mayContinueReading; 080 081 // The line number in the LDIF source on which the problem occurred. 082 private final long lineNumber; 083 084 // A list of the lines comprising the LDIF data being parsed, if available. 085 @Nullable private final List<String> dataLines; 086 087 088 089 /** 090 * Creates a new LDIF exception with the provided information. 091 * 092 * @param message A message explaining the problem that occurred. 093 * It must not be {@code null}. 094 * @param lineNumber The line number in the LDIF source on which the 095 * problem occurred. 096 * @param mayContinueReading Indicates whether it is possible to continue 097 * attempting to read from the LDIF source. 098 */ 099 public LDIFException(@NotNull final String message, final long lineNumber, 100 final boolean mayContinueReading) 101 { 102 this(message, lineNumber, mayContinueReading, (List<CharSequence>) null, 103 null); 104 } 105 106 107 108 /** 109 * Creates a new LDIF exception with the provided information. 110 * 111 * @param message A message explaining the problem that occurred. 112 * It must not be {@code null}. 113 * @param lineNumber The line number in the LDIF source on which the 114 * problem occurred. 115 * @param mayContinueReading Indicates whether it is possible to continue 116 * attempting to read from the LDIF source. 117 * @param cause The underlying exception that triggered this 118 * exception. 119 */ 120 public LDIFException(@NotNull final String message, final long lineNumber, 121 final boolean mayContinueReading, 122 @Nullable final Throwable cause) 123 { 124 this(message, lineNumber, mayContinueReading, (List<CharSequence>) null, 125 cause); 126 } 127 128 129 130 /** 131 * Creates a new LDIF exception with the provided information. 132 * 133 * @param message A message explaining the problem that occurred. 134 * It must not be {@code null}. 135 * @param lineNumber The line number in the LDIF source on which the 136 * problem occurred. 137 * @param mayContinueReading Indicates whether it is possible to continue 138 * attempting to read from the LDIF source. 139 * @param dataLines The lines that comprise the data that could not 140 * be parsed as valid LDIF. It may be 141 * {@code null} if this is not available. 142 * @param cause The underlying exception that triggered this 143 * exception. 144 */ 145 public LDIFException(@NotNull final String message, final long lineNumber, 146 final boolean mayContinueReading, 147 @Nullable final CharSequence[] dataLines, 148 @Nullable final Throwable cause) 149 { 150 this(message, lineNumber, mayContinueReading, 151 (dataLines == null) ? null : Arrays.asList(dataLines), 152 cause); 153 } 154 155 156 157 /** 158 * Creates a new LDIF exception with the provided information. 159 * 160 * @param message A message explaining the problem that occurred. 161 * It must not be {@code null}. 162 * @param lineNumber The line number in the LDIF source on which the 163 * problem occurred. 164 * @param mayContinueReading Indicates whether it is possible to continue 165 * attempting to read from the LDIF source. 166 * @param dataLines The lines that comprise the data that could not 167 * be parsed as valid LDIF. It may be 168 * {@code null} if this is not available. 169 * @param cause The underlying exception that triggered this 170 * exception. 171 */ 172 public LDIFException(@NotNull final String message, final long lineNumber, 173 final boolean mayContinueReading, 174 @Nullable final List<? extends CharSequence> dataLines, 175 @Nullable final Throwable cause) 176 { 177 super(message, cause); 178 179 Validator.ensureNotNull(message); 180 181 this.lineNumber = lineNumber; 182 this.mayContinueReading = mayContinueReading; 183 184 if (dataLines == null) 185 { 186 this.dataLines = null; 187 } 188 else 189 { 190 final ArrayList<String> lineList = new ArrayList<>(dataLines.size()); 191 for (final CharSequence s : dataLines) 192 { 193 lineList.add(s.toString()); 194 } 195 196 this.dataLines = Collections.unmodifiableList(lineList); 197 } 198 } 199 200 201 202 /** 203 * Retrieves the line number on which the problem occurred. 204 * 205 * @return The line number on which the problem occurred. 206 */ 207 public long getLineNumber() 208 { 209 return lineNumber; 210 } 211 212 213 214 /** 215 * Indicates whether it is possible to continue attempting to read from the 216 * LDIF source. 217 * 218 * @return {@code true} if it is possible to continue attempting to read from 219 * the LDIF source, or {@code false} if it is not possible to 220 * continue. 221 */ 222 public boolean mayContinueReading() 223 { 224 return mayContinueReading; 225 } 226 227 228 229 /** 230 * Retrieves the lines comprising the data that could not be parsed as valid 231 * LDIF, if available. 232 * 233 * @return An unmodifiable list of the lines comprising the data that could 234 * not be parsed as valid LDIF, or {@code null} if that is not 235 * available. 236 */ 237 @Nullable() 238 public List<String> getDataLines() 239 { 240 return dataLines; 241 } 242 243 244 245 /** 246 * {@inheritDoc} 247 */ 248 @Override() 249 public void toString(@NotNull final StringBuilder buffer) 250 { 251 final boolean includeCause = 252 Boolean.getBoolean(Debug.PROPERTY_INCLUDE_CAUSE_IN_EXCEPTION_MESSAGES); 253 final boolean includeStackTrace = Boolean.getBoolean( 254 Debug.PROPERTY_INCLUDE_STACK_TRACE_IN_EXCEPTION_MESSAGES); 255 256 toString(buffer, includeCause, includeStackTrace); 257 } 258 259 260 261 /** 262 * Appends a string representation of this {@code LDIFException} to the 263 * provided buffer. 264 * 265 * @param buffer The buffer to which the information should be 266 * appended. This must not be {@code null}. 267 * @param includeCause Indicates whether to include information about 268 * the cause (if any) in the exception message. 269 * @param includeStackTrace Indicates whether to include a condensed 270 * representation of the stack trace in the 271 * exception message. If a stack trace is 272 * included, then the cause (if any) will 273 * automatically be included, regardless of the 274 * value of the {@code includeCause} argument. 275 */ 276 public void toString(@NotNull final StringBuilder buffer, 277 final boolean includeCause, 278 final boolean includeStackTrace) 279 { 280 buffer.append("LDIFException(lineNumber="); 281 buffer.append(lineNumber); 282 buffer.append(", mayContinueReading="); 283 buffer.append(mayContinueReading); 284 buffer.append(", message='"); 285 buffer.append(getMessage()); 286 287 if (dataLines != null) 288 { 289 buffer.append("', dataLines='"); 290 for (final CharSequence s : dataLines) 291 { 292 buffer.append(s); 293 buffer.append("{end-of-line}"); 294 } 295 } 296 297 if (includeStackTrace) 298 { 299 buffer.append(", trace='"); 300 StaticUtils.getStackTrace(getStackTrace(), buffer); 301 buffer.append('\''); 302 } 303 304 if (includeCause || includeStackTrace) 305 { 306 final Throwable cause = getCause(); 307 if (cause != null) 308 { 309 buffer.append(", cause="); 310 buffer.append(StaticUtils.getExceptionMessage(cause, true, 311 includeStackTrace)); 312 } 313 } 314 315 final String ldapSDKVersionString = ", ldapSDKVersion=" + 316 Version.NUMERIC_VERSION_STRING + ", revision=" + Version.REVISION_ID; 317 if (buffer.indexOf(ldapSDKVersionString) < 0) 318 { 319 buffer.append(ldapSDKVersionString); 320 } 321 322 buffer.append(')'); 323 } 324 325 326 327 /** 328 * {@inheritDoc} 329 */ 330 @Override() 331 @NotNull() 332 public String getExceptionMessage() 333 { 334 return toString(); 335 } 336 337 338 339 /** 340 * {@inheritDoc} 341 */ 342 @Override() 343 @NotNull() 344 public String getExceptionMessage(final boolean includeCause, 345 final boolean includeStackTrace) 346 { 347 final StringBuilder buffer = new StringBuilder(); 348 toString(buffer, includeCause, includeStackTrace); 349 return buffer.toString(); 350 } 351}