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