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