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