mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

Matthew Swift
25.33.2012 263d085885df024dca9250cc03c807912b0a7662
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/LDIFEntryReader.java
@@ -6,17 +6,16 @@
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opendj3/legal-notices/CDDLv1_0.txt
 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
 * or http://forgerock.org/license/CDDLv1.0.html.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opendj3/legal-notices/CDDLv1_0.txt.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 * file and include the License file at legal-notices/CDDLv1_0.txt.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
@@ -28,8 +27,6 @@
package org.forgerock.opendj.ldif;
import static org.forgerock.opendj.ldap.CoreMessages.*;
import java.io.IOException;
@@ -41,14 +38,17 @@
import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.i18n.LocalizedIllegalArgumentException;
import org.forgerock.opendj.ldap.*;
import org.forgerock.opendj.ldap.AttributeDescription;
import org.forgerock.opendj.ldap.DN;
import org.forgerock.opendj.ldap.DecodeException;
import org.forgerock.opendj.ldap.Entry;
import org.forgerock.opendj.ldap.LinkedHashMapEntry;
import org.forgerock.opendj.ldap.Matcher;
import org.forgerock.opendj.ldap.schema.Schema;
import org.forgerock.opendj.ldap.schema.SchemaValidationPolicy;
import com.forgerock.opendj.util.Validator;
/**
 * An LDIF entry reader reads attribute value records (entries) using the LDAP
 * Data Interchange Format (LDIF) from a user defined source.
@@ -56,456 +56,373 @@
 * @see <a href="http://tools.ietf.org/html/rfc2849">RFC 2849 - The LDAP Data
 *      Interchange Format (LDIF) - Technical Specification </a>
 */
public final class LDIFEntryReader extends AbstractLDIFReader implements
    EntryReader
{
  // Poison used to indicate end of LDIF.
  private static final Entry EOF = new LinkedHashMapEntry();
public final class LDIFEntryReader extends AbstractLDIFReader implements EntryReader {
    // Poison used to indicate end of LDIF.
    private static final Entry EOF = new LinkedHashMapEntry();
    /**
     * Parses the provided array of LDIF lines as a single LDIF entry.
     *
     * @param ldifLines
     *            The lines of LDIF to be parsed.
     * @return The parsed LDIF entry.
     * @throws LocalizedIllegalArgumentException
     *             If {@code ldifLines} did not contain an LDIF entry, if it
     *             contained multiple entries, if contained malformed LDIF, or
     *             if the entry could not be decoded using the default schema.
     * @throws NullPointerException
     *             If {@code ldifLines} was {@code null}.
     */
    public static Entry valueOfLDIFEntry(final String... ldifLines) {
        final LDIFEntryReader reader = new LDIFEntryReader(ldifLines);
        try {
            if (!reader.hasNext()) {
                // No change record found.
                final LocalizableMessage message =
                        WARN_READ_LDIF_RECORD_NO_CHANGE_RECORD_FOUND.get();
                throw new LocalizedIllegalArgumentException(message);
            }
            final Entry entry = reader.readEntry();
  /**
   * Parses the provided array of LDIF lines as a single LDIF entry.
   *
   * @param ldifLines
   *          The lines of LDIF to be parsed.
   * @return The parsed LDIF entry.
   * @throws LocalizedIllegalArgumentException
   *           If {@code ldifLines} did not contain an LDIF entry, if it
   *           contained multiple entries, if contained malformed LDIF, or if
   *           the entry could not be decoded using the default schema.
   * @throws NullPointerException
   *           If {@code ldifLines} was {@code null}.
   */
  public static Entry valueOfLDIFEntry(final String... ldifLines)
  {
    final LDIFEntryReader reader = new LDIFEntryReader(ldifLines);
    try
    {
      if (!reader.hasNext())
      {
        // No change record found.
        final LocalizableMessage message = WARN_READ_LDIF_RECORD_NO_CHANGE_RECORD_FOUND
            .get();
        throw new LocalizedIllegalArgumentException(message);
      }
            if (reader.hasNext()) {
                // Multiple change records found.
                final LocalizableMessage message =
                        WARN_READ_LDIF_RECORD_MULTIPLE_CHANGE_RECORDS_FOUND.get();
                throw new LocalizedIllegalArgumentException(message);
            }
      final Entry entry = reader.readEntry();
      if (reader.hasNext())
      {
        // Multiple change records found.
        final LocalizableMessage message = WARN_READ_LDIF_RECORD_MULTIPLE_CHANGE_RECORDS_FOUND
            .get();
        throw new LocalizedIllegalArgumentException(message);
      }
      return entry;
    }
    catch (final DecodeException e)
    {
      // Badly formed LDIF.
      throw new LocalizedIllegalArgumentException(e.getMessageObject());
    }
    catch (final IOException e)
    {
      // This should never happen for a String based reader.
      final LocalizableMessage message = WARN_READ_LDIF_RECORD_UNEXPECTED_IO_ERROR
          .get(e.getMessage());
      throw new LocalizedIllegalArgumentException(message);
    }
  }
  private Entry nextEntry = null;
  /**
   * Creates a new LDIF entry reader whose source is the provided input stream.
   *
   * @param in
   *          The input stream to use.
   * @throws NullPointerException
   *           If {@code in} was {@code null}.
   */
  public LDIFEntryReader(final InputStream in)
  {
    super(in);
  }
  /**
   * Creates a new LDIF entry reader which will read lines of LDIF from the
   * provided list of LDIF lines.
   *
   * @param ldifLines
   *          The lines of LDIF to be read.
   * @throws NullPointerException
   *           If {@code ldifLines} was {@code null}.
   */
  public LDIFEntryReader(final List<String> ldifLines)
  {
    super(ldifLines);
  }
  /**
   * Creates a new LDIF entry reader which will read lines of LDIF from the
   * provided array of LDIF lines.
   *
   * @param ldifLines
   *          The lines of LDIF to be read.
   * @throws NullPointerException
   *           If {@code ldifLines} was {@code null}.
   */
  public LDIFEntryReader(final String... ldifLines)
  {
    super(Arrays.asList(ldifLines));
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public void close() throws IOException
  {
    close0();
  }
  /**
   * {@inheritDoc}
   *
   * @throws DecodeException
   *           If the entry could not be decoded because it was malformed.
   */
  @Override
  public boolean hasNext() throws DecodeException, IOException
  {
    return getNextEntry() != EOF;
  }
  /**
   * {@inheritDoc}
   *
   * @throws DecodeException
   *           If the entry could not be decoded because it was malformed.
   */
  @Override
  public Entry readEntry() throws DecodeException, IOException
  {
    if (!hasNext())
    {
      // LDIF reader has completed successfully.
      throw new NoSuchElementException();
            return entry;
        } catch (final DecodeException e) {
            // Badly formed LDIF.
            throw new LocalizedIllegalArgumentException(e.getMessageObject());
        } catch (final IOException e) {
            // This should never happen for a String based reader.
            final LocalizableMessage message =
                    WARN_READ_LDIF_RECORD_UNEXPECTED_IO_ERROR.get(e.getMessage());
            throw new LocalizedIllegalArgumentException(message);
        }
    }
    final Entry entry = nextEntry;
    nextEntry = null;
    return entry;
  }
    private Entry nextEntry = null;
  /**
   * Specifies whether or not all operational attributes should be excluded from
   * any entries that are read from LDIF. The default is {@code false}.
   *
   * @param excludeOperationalAttributes
   *          {@code true} if all operational attributes should be excluded, or
   *          {@code false} otherwise.
   * @return A reference to this {@code LDIFEntryReader}.
   */
  public LDIFEntryReader setExcludeAllOperationalAttributes(
      final boolean excludeOperationalAttributes)
  {
    this.excludeOperationalAttributes = excludeOperationalAttributes;
    return this;
  }
  /**
   * Specifies whether or not all user attributes should be excluded from any
   * entries that are read from LDIF. The default is {@code false}.
   *
   * @param excludeUserAttributes
   *          {@code true} if all user attributes should be excluded, or
   *          {@code false} otherwise.
   * @return A reference to this {@code LDIFEntryReader}.
   */
  public LDIFEntryReader setExcludeAllUserAttributes(
      final boolean excludeUserAttributes)
  {
    this.excludeUserAttributes = excludeUserAttributes;
    return this;
  }
  /**
   * Excludes the named attribute from any entries that are read from LDIF. By
   * default all attributes are included unless explicitly excluded.
   *
   * @param attributeDescription
   *          The name of the attribute to be excluded.
   * @return A reference to this {@code LDIFEntryReader}.
   */
  public LDIFEntryReader setExcludeAttribute(
      final AttributeDescription attributeDescription)
  {
    Validator.ensureNotNull(attributeDescription);
    excludeAttributes.add(attributeDescription);
    return this;
  }
  /**
   * Excludes all entries beneath the named entry (inclusive) from being read
   * from LDIF. By default all entries are written unless explicitly excluded or
   * included by branches or filters.
   *
   * @param excludeBranch
   *          The distinguished name of the branch to be excluded.
   * @return A reference to this {@code LDIFEntryReader}.
   */
  public LDIFEntryReader setExcludeBranch(final DN excludeBranch)
  {
    Validator.ensureNotNull(excludeBranch);
    excludeBranches.add(excludeBranch);
    return this;
  }
  /**
   * Excludes all entries which match the provided filter matcher from being
   * read from LDIF. By default all entries are read unless explicitly excluded
   * or included by branches or filters.
   *
   * @param excludeFilter
   *          The filter matcher.
   * @return A reference to this {@code LDIFEntryReader}.
   */
  public LDIFEntryReader setExcludeFilter(final Matcher excludeFilter)
  {
    Validator.ensureNotNull(excludeFilter);
    excludeFilters.add(excludeFilter);
    return this;
  }
  /**
   * Ensures that the named attribute is not excluded from any entries that are
   * read from LDIF. By default all attributes are included unless explicitly
   * excluded.
   *
   * @param attributeDescription
   *          The name of the attribute to be included.
   * @return A reference to this {@code LDIFEntryReader}.
   */
  public LDIFEntryReader setIncludeAttribute(
      final AttributeDescription attributeDescription)
  {
    Validator.ensureNotNull(attributeDescription);
    includeAttributes.add(attributeDescription);
    return this;
  }
  /**
   * Ensures that all entries beneath the named entry (inclusive) are read from
   * LDIF. By default all entries are written unless explicitly excluded or
   * included by branches or filters.
   *
   * @param includeBranch
   *          The distinguished name of the branch to be included.
   * @return A reference to this {@code LDIFEntryReader}.
   */
  public LDIFEntryReader setIncludeBranch(final DN includeBranch)
  {
    Validator.ensureNotNull(includeBranch);
    includeBranches.add(includeBranch);
    return this;
  }
  /**
   * Ensures that all entries which match the provided filter matcher are read
   * from LDIF. By default all entries are read unless explicitly excluded or
   * included by branches or filters.
   *
   * @param includeFilter
   *          The filter matcher.
   * @return A reference to this {@code LDIFEntryReader}.
   */
  public LDIFEntryReader setIncludeFilter(final Matcher includeFilter)
  {
    Validator.ensureNotNull(includeFilter);
    includeFilters.add(includeFilter);
    return this;
  }
  /**
   * Sets the rejected record listener which should be notified whenever an LDIF
   * record is skipped, malformed, or fails schema validation.
   * <p>
   * By default the {@link RejectedLDIFListener#FAIL_FAST} listener is used.
   *
   * @param listener
   *          The rejected record listener.
   * @return A reference to this {@code LDIFEntryReader}.
   */
  public LDIFEntryReader setRejectedLDIFListener(
      final RejectedLDIFListener listener)
  {
    this.rejectedRecordListener = listener;
    return this;
  }
  /**
   * Sets the schema which should be used for decoding entries that are read
   * from LDIF. The default schema is used if no other is specified.
   *
   * @param schema
   *          The schema which should be used for decoding entries that are read
   *          from LDIF.
   * @return A reference to this {@code LDIFEntryReader}.
   */
  public LDIFEntryReader setSchema(final Schema schema)
  {
    Validator.ensureNotNull(schema);
    this.schema = schemaValidationPolicy.checkAttributesAndObjectClasses()
        .needsChecking() ? schema.asStrictSchema() : schema.asNonStrictSchema();
    return this;
  }
  /**
   * Specifies the schema validation which should be used when reading LDIF
   * entry records. If attribute value validation is enabled then all checks
   * will be performed.
   * <p>
   * Schema validation is disabled by default.
   * <p>
   * <b>NOTE:</b> this method copies the provided policy so changes made to it
   * after this method has been called will have no effect.
   *
   * @param policy
   *          The schema validation which should be used when reading LDIF entry
   *          records.
   * @return A reference to this {@code LDIFEntryReader}.
   */
  public LDIFEntryReader setSchemaValidationPolicy(
      final SchemaValidationPolicy policy)
  {
    this.schemaValidationPolicy = SchemaValidationPolicy.copyOf(policy);
    this.schema = schemaValidationPolicy.checkAttributesAndObjectClasses()
        .needsChecking() ? schema.asStrictSchema() : schema.asNonStrictSchema();
    return this;
  }
  private Entry getNextEntry() throws DecodeException, IOException
  {
    while (nextEntry == null)
    {
      // Read the set of lines that make up the next entry.
      final LDIFRecord record = readLDIFRecord();
      if (record == null)
      {
        nextEntry = EOF;
        break;
      }
      try
      {
        // Read the DN of the entry and see if it is one that should be
        // included in the import.
        final DN entryDN = readLDIFRecordDN(record);
        if (entryDN == null)
        {
          // Skip version record.
          continue;
        }
        // Skip if branch containing the entry DN is excluded.
        if (isBranchExcluded(entryDN))
        {
          final LocalizableMessage message = ERR_LDIF_ENTRY_EXCLUDED_BY_DN.get(
              record.lineNumber, entryDN.toString());
          handleSkippedRecord(record, message);
          continue;
        }
        // Use an Entry for the AttributeSequence.
        final Entry entry = new LinkedHashMapEntry(entryDN);
        boolean schemaValidationFailure = false;
        final List<LocalizableMessage> schemaErrors = new LinkedList<LocalizableMessage>();
        while (record.iterator.hasNext())
        {
          final String ldifLine = record.iterator.next();
          if (!readLDIFRecordAttributeValue(record, ldifLine, entry,
              schemaErrors))
          {
            schemaValidationFailure = true;
          }
        }
        // Skip if the entry is excluded by any filters.
        if (isEntryExcluded(entry))
        {
          final LocalizableMessage message = ERR_LDIF_ENTRY_EXCLUDED_BY_FILTER
              .get(record.lineNumber, entryDN.toString());
          handleSkippedRecord(record, message);
          continue;
        }
        if (!schema.validateEntry(entry, schemaValidationPolicy, schemaErrors))
        {
          schemaValidationFailure = true;
        }
        if (schemaValidationFailure)
        {
          handleSchemaValidationFailure(record, schemaErrors);
          continue;
        }
        if (!schemaErrors.isEmpty())
        {
          handleSchemaValidationWarning(record, schemaErrors);
        }
        nextEntry = entry;
      }
      catch (final DecodeException e)
      {
        handleMalformedRecord(record, e.getMessageObject());
        continue;
      }
    /**
     * Creates a new LDIF entry reader whose source is the provided input
     * stream.
     *
     * @param in
     *            The input stream to use.
     * @throws NullPointerException
     *             If {@code in} was {@code null}.
     */
    public LDIFEntryReader(final InputStream in) {
        super(in);
    }
    return nextEntry;
  }
    /**
     * Creates a new LDIF entry reader which will read lines of LDIF from the
     * provided list of LDIF lines.
     *
     * @param ldifLines
     *            The lines of LDIF to be read.
     * @throws NullPointerException
     *             If {@code ldifLines} was {@code null}.
     */
    public LDIFEntryReader(final List<String> ldifLines) {
        super(ldifLines);
    }
    /**
     * Creates a new LDIF entry reader which will read lines of LDIF from the
     * provided array of LDIF lines.
     *
     * @param ldifLines
     *            The lines of LDIF to be read.
     * @throws NullPointerException
     *             If {@code ldifLines} was {@code null}.
     */
    public LDIFEntryReader(final String... ldifLines) {
        super(Arrays.asList(ldifLines));
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public void close() throws IOException {
        close0();
    }
    /**
     * {@inheritDoc}
     *
     * @throws DecodeException
     *             If the entry could not be decoded because it was malformed.
     */
    @Override
    public boolean hasNext() throws DecodeException, IOException {
        return getNextEntry() != EOF;
    }
    /**
     * {@inheritDoc}
     *
     * @throws DecodeException
     *             If the entry could not be decoded because it was malformed.
     */
    @Override
    public Entry readEntry() throws DecodeException, IOException {
        if (!hasNext()) {
            // LDIF reader has completed successfully.
            throw new NoSuchElementException();
        }
        final Entry entry = nextEntry;
        nextEntry = null;
        return entry;
    }
    /**
     * Specifies whether or not all operational attributes should be excluded
     * from any entries that are read from LDIF. The default is {@code false}.
     *
     * @param excludeOperationalAttributes
     *            {@code true} if all operational attributes should be excluded,
     *            or {@code false} otherwise.
     * @return A reference to this {@code LDIFEntryReader}.
     */
    public LDIFEntryReader setExcludeAllOperationalAttributes(
            final boolean excludeOperationalAttributes) {
        this.excludeOperationalAttributes = excludeOperationalAttributes;
        return this;
    }
    /**
     * Specifies whether or not all user attributes should be excluded from any
     * entries that are read from LDIF. The default is {@code false}.
     *
     * @param excludeUserAttributes
     *            {@code true} if all user attributes should be excluded, or
     *            {@code false} otherwise.
     * @return A reference to this {@code LDIFEntryReader}.
     */
    public LDIFEntryReader setExcludeAllUserAttributes(final boolean excludeUserAttributes) {
        this.excludeUserAttributes = excludeUserAttributes;
        return this;
    }
    /**
     * Excludes the named attribute from any entries that are read from LDIF. By
     * default all attributes are included unless explicitly excluded.
     *
     * @param attributeDescription
     *            The name of the attribute to be excluded.
     * @return A reference to this {@code LDIFEntryReader}.
     */
    public LDIFEntryReader setExcludeAttribute(final AttributeDescription attributeDescription) {
        Validator.ensureNotNull(attributeDescription);
        excludeAttributes.add(attributeDescription);
        return this;
    }
    /**
     * Excludes all entries beneath the named entry (inclusive) from being read
     * from LDIF. By default all entries are written unless explicitly excluded
     * or included by branches or filters.
     *
     * @param excludeBranch
     *            The distinguished name of the branch to be excluded.
     * @return A reference to this {@code LDIFEntryReader}.
     */
    public LDIFEntryReader setExcludeBranch(final DN excludeBranch) {
        Validator.ensureNotNull(excludeBranch);
        excludeBranches.add(excludeBranch);
        return this;
    }
    /**
     * Excludes all entries which match the provided filter matcher from being
     * read from LDIF. By default all entries are read unless explicitly
     * excluded or included by branches or filters.
     *
     * @param excludeFilter
     *            The filter matcher.
     * @return A reference to this {@code LDIFEntryReader}.
     */
    public LDIFEntryReader setExcludeFilter(final Matcher excludeFilter) {
        Validator.ensureNotNull(excludeFilter);
        excludeFilters.add(excludeFilter);
        return this;
    }
    /**
     * Ensures that the named attribute is not excluded from any entries that
     * are read from LDIF. By default all attributes are included unless
     * explicitly excluded.
     *
     * @param attributeDescription
     *            The name of the attribute to be included.
     * @return A reference to this {@code LDIFEntryReader}.
     */
    public LDIFEntryReader setIncludeAttribute(final AttributeDescription attributeDescription) {
        Validator.ensureNotNull(attributeDescription);
        includeAttributes.add(attributeDescription);
        return this;
    }
    /**
     * Ensures that all entries beneath the named entry (inclusive) are read
     * from LDIF. By default all entries are written unless explicitly excluded
     * or included by branches or filters.
     *
     * @param includeBranch
     *            The distinguished name of the branch to be included.
     * @return A reference to this {@code LDIFEntryReader}.
     */
    public LDIFEntryReader setIncludeBranch(final DN includeBranch) {
        Validator.ensureNotNull(includeBranch);
        includeBranches.add(includeBranch);
        return this;
    }
    /**
     * Ensures that all entries which match the provided filter matcher are read
     * from LDIF. By default all entries are read unless explicitly excluded or
     * included by branches or filters.
     *
     * @param includeFilter
     *            The filter matcher.
     * @return A reference to this {@code LDIFEntryReader}.
     */
    public LDIFEntryReader setIncludeFilter(final Matcher includeFilter) {
        Validator.ensureNotNull(includeFilter);
        includeFilters.add(includeFilter);
        return this;
    }
    /**
     * Sets the rejected record listener which should be notified whenever an
     * LDIF record is skipped, malformed, or fails schema validation.
     * <p>
     * By default the {@link RejectedLDIFListener#FAIL_FAST} listener is used.
     *
     * @param listener
     *            The rejected record listener.
     * @return A reference to this {@code LDIFEntryReader}.
     */
    public LDIFEntryReader setRejectedLDIFListener(final RejectedLDIFListener listener) {
        this.rejectedRecordListener = listener;
        return this;
    }
    /**
     * Sets the schema which should be used for decoding entries that are read
     * from LDIF. The default schema is used if no other is specified.
     *
     * @param schema
     *            The schema which should be used for decoding entries that are
     *            read from LDIF.
     * @return A reference to this {@code LDIFEntryReader}.
     */
    public LDIFEntryReader setSchema(final Schema schema) {
        Validator.ensureNotNull(schema);
        this.schema =
                schemaValidationPolicy.checkAttributesAndObjectClasses().needsChecking() ? schema
                        .asStrictSchema() : schema.asNonStrictSchema();
        return this;
    }
    /**
     * Specifies the schema validation which should be used when reading LDIF
     * entry records. If attribute value validation is enabled then all checks
     * will be performed.
     * <p>
     * Schema validation is disabled by default.
     * <p>
     * <b>NOTE:</b> this method copies the provided policy so changes made to it
     * after this method has been called will have no effect.
     *
     * @param policy
     *            The schema validation which should be used when reading LDIF
     *            entry records.
     * @return A reference to this {@code LDIFEntryReader}.
     */
    public LDIFEntryReader setSchemaValidationPolicy(final SchemaValidationPolicy policy) {
        this.schemaValidationPolicy = SchemaValidationPolicy.copyOf(policy);
        this.schema =
                schemaValidationPolicy.checkAttributesAndObjectClasses().needsChecking() ? schema
                        .asStrictSchema() : schema.asNonStrictSchema();
        return this;
    }
    private Entry getNextEntry() throws DecodeException, IOException {
        while (nextEntry == null) {
            // Read the set of lines that make up the next entry.
            final LDIFRecord record = readLDIFRecord();
            if (record == null) {
                nextEntry = EOF;
                break;
            }
            try {
                // Read the DN of the entry and see if it is one that should be
                // included in the import.
                final DN entryDN = readLDIFRecordDN(record);
                if (entryDN == null) {
                    // Skip version record.
                    continue;
                }
                // Skip if branch containing the entry DN is excluded.
                if (isBranchExcluded(entryDN)) {
                    final LocalizableMessage message =
                            ERR_LDIF_ENTRY_EXCLUDED_BY_DN
                                    .get(record.lineNumber, entryDN.toString());
                    handleSkippedRecord(record, message);
                    continue;
                }
                // Use an Entry for the AttributeSequence.
                final Entry entry = new LinkedHashMapEntry(entryDN);
                boolean schemaValidationFailure = false;
                final List<LocalizableMessage> schemaErrors = new LinkedList<LocalizableMessage>();
                while (record.iterator.hasNext()) {
                    final String ldifLine = record.iterator.next();
                    if (!readLDIFRecordAttributeValue(record, ldifLine, entry, schemaErrors)) {
                        schemaValidationFailure = true;
                    }
                }
                // Skip if the entry is excluded by any filters.
                if (isEntryExcluded(entry)) {
                    final LocalizableMessage message =
                            ERR_LDIF_ENTRY_EXCLUDED_BY_FILTER.get(record.lineNumber, entryDN
                                    .toString());
                    handleSkippedRecord(record, message);
                    continue;
                }
                if (!schema.validateEntry(entry, schemaValidationPolicy, schemaErrors)) {
                    schemaValidationFailure = true;
                }
                if (schemaValidationFailure) {
                    handleSchemaValidationFailure(record, schemaErrors);
                    continue;
                }
                if (!schemaErrors.isEmpty()) {
                    handleSchemaValidationWarning(record, schemaErrors);
                }
                nextEntry = entry;
            } catch (final DecodeException e) {
                handleMalformedRecord(record, e.getMessageObject());
                continue;
            }
        }
        return nextEntry;
    }
}