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

matthew_swift
11.03.2006 ad8075db9d1ed81528a069d446c27c7e2edbf1d9
Implement a test suite for the LDIFReader class. Performed
refactoring to reduce the amount of code duplication and
improve the coupling between the LDIFReader class and the
ChangeRecordEntry classes.


1 files added
12 files modified
3602 ■■■■ changed files
opendj-sdk/opends/src/server/org/opends/server/tools/LDAPModify.java 8 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/util/AddChangeRecordEntry.java 72 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/util/ChangeRecordEntry.java 62 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/util/DeleteChangeRecordEntry.java 40 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/util/LDIFReader.java 1833 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/util/ModifyChangeRecordEntry.java 124 ●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/util/ModifyDNChangeRecordEntry.java 183 ●●●● patch | view | raw | blame | history
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/util/TestAddChangeRecordEntry.java 68 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/util/TestChangeRecordEntry.java 32 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/util/TestDeleteChangeRecordEntry.java 40 ●●●● patch | view | raw | blame | history
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/util/TestLDIFReader.java 980 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/util/TestModifyChangeRecordEntry.java 72 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/util/TestModifyDNChangeRecordEntry.java 88 ●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/tools/LDAPModify.java
@@ -49,6 +49,7 @@
import org.opends.server.protocols.ldap.LDAPException;
import org.opends.server.protocols.ldap.LDAPFilter;
import org.opends.server.protocols.ldap.LDAPMessage;
import org.opends.server.protocols.ldap.LDAPModification;
import org.opends.server.protocols.ldap.ModifyRequestProtocolOp;
import org.opends.server.protocols.ldap.ModifyResponseProtocolOp;
import org.opends.server.protocols.ldap.ModifyDNRequestProtocolOp;
@@ -236,7 +237,7 @@
        case ADD:
          operationType = "ADD";
          AddChangeRecordEntry addEntry = (AddChangeRecordEntry) entry;
          ArrayList<Attribute> attrs = addEntry.getAttributes();
          List<Attribute> attrs = addEntry.getAttributes();
          ArrayList<LDAPAttribute> attributes =
              new ArrayList<LDAPAttribute>(attrs.size());
          for(Attribute a : attrs)
@@ -256,8 +257,9 @@
        case MODIFY:
          operationType = "MODIFY";
          ModifyChangeRecordEntry modEntry = (ModifyChangeRecordEntry) entry;
          protocolOp = new ModifyRequestProtocolOp(asn1OctetStr,
                                                   modEntry.getModifications());
          ArrayList<LDAPModification> mods =
            new ArrayList<LDAPModification>(modEntry.getModifications());
          protocolOp = new ModifyRequestProtocolOp(asn1OctetStr, mods);
          msgID = MSGID_PROCESSING_OPERATION;
          System.out.println(getMessage(msgID, operationType, asn1OctetStr));
          break;
opendj-sdk/opends/src/server/org/opends/server/util/AddChangeRecordEntry.java
@@ -32,8 +32,9 @@
import static org.opends.server.loggers.Debug.debugEnter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.opends.server.types.Attribute;
import org.opends.server.types.AttributeType;
@@ -58,28 +59,35 @@
  /**
   * The entry attributes for this operation.
   */
  private HashMap<AttributeType,ArrayList<Attribute>> entryAttributes;
  private final List<Attribute> attributes;
  // The LDIF reader instance
  private LDIFReader reader;
  /**
   * Creates a new entry with the provided information.
   *
   * @param  dn      The distinguished name for this entry.
   * @param  reader  The LDIF reader instance used to read the entries.
   * @param dn
   *          The distinguished name for this entry.
   * @param attributes
   *          The entry attributes for this operation.
   */
  public AddChangeRecordEntry(DN dn, LDIFReader reader)
  public AddChangeRecordEntry(DN dn,
      Map<AttributeType,List<Attribute>> attributes)
  {
    super(dn, reader);
    super(dn);
    assert debugConstructor(CLASS_NAME, String.valueOf(dn),
                            String.valueOf(reader));
                            String.valueOf(attributes));
    this.reader = reader;
    entryAttributes = new HashMap<AttributeType, ArrayList<Attribute>>();
    this.attributes = new ArrayList<Attribute>(attributes.size());
    for (List<Attribute> list : attributes.values())
    {
      for (Attribute a : list)
      {
        this.attributes.add(a);
      }
    }
  }
@@ -97,45 +105,19 @@
  }
  /**
   * Retrieves the entire set of attributes for this entry.
   * The caller must not modify the contents of this list.
   * <p>
   * The returned list is read-only.
   *
   * @return  The entire set of attributes for this entry.
   * @return The entire unmodifiable list of attributes for this entry.
   */
  public ArrayList<Attribute> getAttributes()
  public List<Attribute> getAttributes()
  {
    assert debugEnter(CLASS_NAME, "getAttributes");
    ArrayList<Attribute> attributes = new ArrayList<Attribute>();
    for (ArrayList<Attribute> list : entryAttributes.values())
    {
      for (Attribute a : list)
      {
        attributes.add(a);
      }
    }
    return attributes;
  }
  /**
   * Parse the lines and populate the internal structures.
   *
   * @param lines       The lines to parse.
   * @param lineNumber  The current line number
   *
   * @exception LDIFException if there is an error during parsing.
   */
  public void parse(LinkedList<StringBuilder> lines, long lineNumber)
    throws LDIFException
  {
    assert debugEnter(CLASS_NAME, "parse", String.valueOf(lines),
                      String.valueOf(lineNumber));
    for(StringBuilder line : lines)
    {
      reader.readAttribute(lines, line, getDN(), entryAttributes);
    }
    return Collections.unmodifiableList(attributes);
  }
}
opendj-sdk/opends/src/server/org/opends/server/util/ChangeRecordEntry.java
@@ -31,11 +31,7 @@
import static org.opends.server.loggers.Debug.debugConstructor;
import static org.opends.server.loggers.Debug.debugEnter;
import java.util.ArrayList;
import java.util.LinkedList;
import org.opends.server.types.DN;
import org.opends.server.types.RDN;
@@ -58,30 +54,6 @@
  /**
   * Creates a new entry with the provided information.
   *
   * @param  dn      The distinguished name for this entry.
   * @param  reader  The LDIF reader.
   */
  protected ChangeRecordEntry(DN dn, LDIFReader reader)
  {
    assert debugConstructor(CLASS_NAME, String.valueOf(dn),
                            String.valueOf(reader));
    if (dn == null)
    {
      this.dn = new DN(new ArrayList<RDN>(0));
    }
    else
    {
      this.dn = dn;
    }
  }
  /**
   * Creates a new change record entry with the provided information.
   *
   * @param  dn  The distinguished name for this change record entry.
@@ -116,44 +88,10 @@
  /**
   * Specifies the distinguished name for this entry.
   *
   * @param  dn  The distinguished name for this entry.
   */
  public final void setDN(DN dn)
  {
    assert debugEnter(CLASS_NAME, "setDN", String.valueOf(dn));
    if (dn == null)
    {
      this.dn = new DN(new ArrayList<RDN>(0));
    }
    else
    {
      this.dn = dn;
    }
  }
  /**
   * Retrieves the name of the change operation type.
   *
   * @return  The name of the change operation type.
   */
  public abstract ChangeOperationType getChangeOperationType();
  /**
   * Parse and populate internal structures from the specified lines.
   * @param lines The list of lines to parse from.
   * @param lineNumber The current line number during the parsing.
   *
   * @exception LDIFException If there is a parsing error.
   */
  public abstract void parse(LinkedList<StringBuilder> lines, long lineNumber)
         throws LDIFException;
}
opendj-sdk/opends/src/server/org/opends/server/util/DeleteChangeRecordEntry.java
@@ -30,16 +30,11 @@
import static org.opends.server.loggers.Debug.debugConstructor;
import static org.opends.server.loggers.Debug.debugEnter;
import static org.opends.server.messages.MessageHandler.getMessage;
import static org.opends.server.messages.UtilityMessages.*;
import java.util.LinkedList;
import org.opends.server.types.DN;
/**
 * This class defines a data structure for a change record entry for
 * an delete operation.  It includes a DN and a set of attributes, as well as
@@ -59,14 +54,12 @@
   * Creates a new entry with the provided information.
   *
   * @param  dn      The distinguished name for this entry.
   * @param  reader  The LDIFReader instance used to read the entries.
   */
  public DeleteChangeRecordEntry(DN dn, LDIFReader reader)
  public DeleteChangeRecordEntry(DN dn)
  {
    super(dn, reader);
    assert debugConstructor(CLASS_NAME, String.valueOf(dn),
                            String.valueOf(reader));
    super(dn);
    assert debugConstructor(CLASS_NAME, String.valueOf(dn));
  }
@@ -83,32 +76,5 @@
    return ChangeOperationType.DELETE;
  }
  /**
   * Parse the lines and populate the internal structures.
   *
   * @param lines       The lines to parse.
   * @param lineNumber  The current line number.
   *
   * @exception LDIFException if there is an error during parsing.
   */
  public void parse(LinkedList<StringBuilder> lines, long lineNumber)
         throws LDIFException
  {
    assert debugEnter(CLASS_NAME, "parse", String.valueOf(lines),
                      String.valueOf(lineNumber));
    if(! lines.isEmpty())
    {
      int msgID = MSGID_LDIF_INVALID_DELETE_ATTRIBUTES;
      String message = getMessage(msgID);
      throw new LDIFException(msgID, message, lineNumber, true);
    }
  }
}
opendj-sdk/opends/src/server/org/opends/server/util/LDIFReader.java
@@ -28,11 +28,17 @@
import static org.opends.server.loggers.Debug.*;
import static org.opends.server.loggers.Error.logError;
import static org.opends.server.messages.MessageHandler.getMessage;
import static org.opends.server.messages.UtilityMessages.*;
import static org.opends.server.util.StaticUtils.toLowerCase;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
@@ -45,25 +51,22 @@
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.PluginConfigManager;
import org.opends.server.protocols.asn1.ASN1OctetString;
import org.opends.server.protocols.ldap.LDAPAttribute;
import org.opends.server.protocols.ldap.LDAPModification;
import org.opends.server.types.Attribute;
import org.opends.server.types.AttributeType;
import org.opends.server.types.AttributeValue;
import org.opends.server.types.DN;
import org.opends.server.types.DebugLogCategory;
import org.opends.server.types.DebugLogSeverity;
import org.opends.server.types.DN;
import org.opends.server.types.Entry;
import org.opends.server.types.ErrorLogCategory;
import org.opends.server.types.ErrorLogSeverity;
import org.opends.server.types.LDIFImportConfig;
import org.opends.server.types.ModificationType;
import org.opends.server.types.ObjectClass;
import org.opends.server.types.RDN;
import static org.opends.server.loggers.Debug.*;
import static org.opends.server.loggers.Error.*;
import static org.opends.server.messages.MessageHandler.*;
import static org.opends.server.messages.UtilityMessages.*;
import static org.opends.server.util.StaticUtils.*;
/**
@@ -71,7 +74,7 @@
 * provides support for both standard entries and change entries (as would be
 * used with a tool like ldapmodify).
 */
public class LDIFReader
public final class LDIFReader
{
  /**
   * The fully-qualified name of this class for debugging purposes.
@@ -310,28 +313,7 @@
          String message = getMessage(msgID, String.valueOf(entryDN),
                                      lastEntryLineNumber,
                                      invalidReason.toString());
          BufferedWriter rejectWriter = importConfig.getRejectWriter();
          if (rejectWriter != null)
          {
            try
            {
              rejectWriter.write("# " + message);
              rejectWriter.newLine();
              for (StringBuilder sb : lines)
              {
                rejectWriter.write(sb.toString());
                rejectWriter.newLine();
              }
              rejectWriter.newLine();
            }
            catch (Exception e)
            {
              assert debugException(CLASS_NAME, "readEntry", e);
            }
          }
          logToRejectWriter(lines, message);
          entriesRejected++;
          throw new LDIFException(msgID, message, lastEntryLineNumber, true);
        }
@@ -391,19 +373,19 @@
      {
        if(changeType.equals("add"))
        {
          entry = new AddChangeRecordEntry(entryDN, this);
          entry = parseAddChangeRecordEntry(entryDN, lines);
        } else if (changeType.equals("delete"))
        {
          entry = new DeleteChangeRecordEntry(entryDN, this);
          entry = parseDeleteChangeRecordEntry(entryDN, lines);
        } else if (changeType.equals("modify"))
        {
          entry = new ModifyChangeRecordEntry(entryDN, this);
          entry = parseModifyChangeRecordEntry(entryDN, lines);
        } else if (changeType.equals("modrdn"))
        {
          entry = new ModifyDNChangeRecordEntry(entryDN, this);
          entry = parseModifyDNChangeRecordEntry(entryDN, lines);
        } else if (changeType.equals("moddn"))
        {
          entry = new ModifyDNChangeRecordEntry(entryDN, this);
          entry = parseModifyDNChangeRecordEntry(entryDN, lines);
        } else
        {
          int msgID = MSGID_LDIF_INVALID_CHANGETYPE_ATTRIBUTE;
@@ -416,7 +398,7 @@
        // default to "add"?
        if(defaultAdd)
        {
          entry = new AddChangeRecordEntry(entryDN, this);
          entry = parseAddChangeRecordEntry(entryDN, lines);
        } else
        {
          int msgID = MSGID_LDIF_INVALID_CHANGETYPE_ATTRIBUTE;
@@ -426,16 +408,12 @@
        }
      }
      // Parse the lines to populate the change record entry data structures.
      entry.parse(lines, lastEntryLineNumber);
      return entry;
    }
  }
  /**
   * Reads a set of lines from the next entry in the LDIF source.
   *
@@ -512,23 +490,7 @@
        {
          int    msgID   = MSGID_LDIF_INVALID_LEADING_SPACE;
          String message = getMessage(msgID, lineNumber, line);
          BufferedWriter rejectWriter = importConfig.getRejectWriter();
          if (rejectWriter != null)
          {
            rejectWriter.write("# " + message);
            rejectWriter.newLine();
            for (StringBuilder sb : lines)
            {
              rejectWriter.write(sb.toString());
              rejectWriter.newLine();
            }
            rejectWriter.write(line);
            rejectWriter.newLine();
            rejectWriter.newLine();
          }
          logToRejectWriter(lines, message);
          throw new LDIFException(msgID, message, lineNumber, false);
        }
      }
@@ -584,26 +546,7 @@
      int    msgID   = MSGID_LDIF_NO_ATTR_NAME;
      String message = getMessage(msgID, lastEntryLineNumber, line.toString());
      BufferedWriter rejectWriter = importConfig.getRejectWriter();
      if (rejectWriter != null)
      {
        try
        {
          rejectWriter.write("# " + message);
          rejectWriter.newLine();
          for (StringBuilder sb : lines)
          {
            rejectWriter.write(sb.toString());
            rejectWriter.newLine();
          }
          rejectWriter.newLine();
        }
        catch (Exception e)
        {
          assert debugException(CLASS_NAME, "readDN", e);
        }
      }
      logToRejectWriter(lines, message);
      throw new LDIFException(msgID, message, lastEntryLineNumber, true);
    }
@@ -619,26 +562,7 @@
      int    msgID   = MSGID_LDIF_NO_DN;
      String message = getMessage(msgID, lastEntryLineNumber, line.toString());
      BufferedWriter rejectWriter = importConfig.getRejectWriter();
      if (rejectWriter != null)
      {
        try
        {
          rejectWriter.write("# " + message);
          rejectWriter.newLine();
          for (StringBuilder sb : lines)
          {
            rejectWriter.write(sb.toString());
            rejectWriter.newLine();
          }
          rejectWriter.newLine();
        }
        catch (Exception e)
        {
          assert debugException(CLASS_NAME, "readDN", e);
        }
      }
      logToRejectWriter(lines, message);
      throw new LDIFException(msgID, message, lastEntryLineNumber, true);
    }
@@ -679,26 +603,7 @@
        String message = getMessage(msgID, lastEntryLineNumber, line,
                                    String.valueOf(e));
        BufferedWriter rejectWriter = importConfig.getRejectWriter();
        if (rejectWriter != null)
        {
          try
          {
            rejectWriter.write("# " + message);
            rejectWriter.newLine();
            for (StringBuilder sb : lines)
            {
              rejectWriter.write(sb.toString());
              rejectWriter.newLine();
            }
            rejectWriter.newLine();
          }
          catch (Exception e2)
          {
            assert debugException(CLASS_NAME, "readDN", e2);
          }
        }
        logToRejectWriter(lines, message);
        throw new LDIFException(msgID, message, lastEntryLineNumber, true, e);
      }
@@ -715,26 +620,7 @@
        String message = getMessage(msgID, lastEntryLineNumber, line.toString(),
                                    de.getErrorMessage());
        BufferedWriter rejectWriter = importConfig.getRejectWriter();
        if (rejectWriter != null)
        {
          try
          {
            rejectWriter.write("# " + message);
            rejectWriter.newLine();
            for (StringBuilder sb : lines)
            {
              rejectWriter.write(sb.toString());
              rejectWriter.newLine();
            }
            rejectWriter.newLine();
          }
          catch (Exception e)
          {
            assert debugException(CLASS_NAME, "readDN", e);
          }
        }
        logToRejectWriter(lines, message);
        throw new LDIFException(msgID, message, lastEntryLineNumber, true, de);
      }
@@ -746,26 +632,7 @@
        String message = getMessage(msgID, lastEntryLineNumber, line.toString(),
                                    String.valueOf(e));
        BufferedWriter rejectWriter = importConfig.getRejectWriter();
        if (rejectWriter != null)
        {
          try
          {
            rejectWriter.write("# " + message);
            rejectWriter.newLine();
            for (StringBuilder sb : lines)
            {
              rejectWriter.write(sb.toString());
              rejectWriter.newLine();
            }
            rejectWriter.newLine();
          }
          catch (Exception e2)
          {
            assert debugException(CLASS_NAME, "readDN", e2);
          }
        }
        logToRejectWriter(lines, message);
        throw new LDIFException(msgID, message, lastEntryLineNumber, true, e);
      }
@@ -794,26 +661,7 @@
        String message = getMessage(msgID, lastEntryLineNumber, line.toString(),
                                    de.getErrorMessage());
        BufferedWriter rejectWriter = importConfig.getRejectWriter();
        if (rejectWriter != null)
        {
          try
          {
            rejectWriter.write("# " + message);
            rejectWriter.newLine();
            for (StringBuilder sb : lines)
            {
              rejectWriter.write(sb.toString());
              rejectWriter.newLine();
            }
            rejectWriter.newLine();
          }
          catch (Exception e)
          {
            assert debugException(CLASS_NAME, "readDN", e);
          }
        }
        logToRejectWriter(lines, message);
        throw new LDIFException(msgID, message, lastEntryLineNumber, true, de);
      }
@@ -825,26 +673,7 @@
        String message = getMessage(msgID, lastEntryLineNumber, line.toString(),
                                    String.valueOf(e));
        BufferedWriter rejectWriter = importConfig.getRejectWriter();
        if (rejectWriter != null)
        {
          try
          {
            rejectWriter.write("# " + message);
            rejectWriter.newLine();
            for (StringBuilder sb : lines)
            {
              rejectWriter.write(sb.toString());
              rejectWriter.newLine();
            }
            rejectWriter.newLine();
          }
          catch (Exception e2)
          {
            assert debugException(CLASS_NAME, "readDN", e2);
          }
        }
        logToRejectWriter(lines, message);
        throw new LDIFException(msgID, message, lastEntryLineNumber, true, e);
      }
@@ -852,6 +681,7 @@
  }
  /**
   * Reads the changetype of the entry from the provided list of lines.  If
   * there is no changetype attribute then an add is assumed.
@@ -882,28 +712,7 @@
    {
      int    msgID   = MSGID_LDIF_NO_ATTR_NAME;
      String message = getMessage(msgID, lastEntryLineNumber, line.toString());
      BufferedWriter rejectWriter = importConfig.getRejectWriter();
      if (rejectWriter != null)
      {
        try
        {
          rejectWriter.write("# " + message);
          rejectWriter.newLine();
          for (StringBuilder sb : lines)
          {
            rejectWriter.write(sb.toString());
            rejectWriter.newLine();
          }
          rejectWriter.newLine();
        }
        catch (Exception e)
        {
          assert debugException(CLASS_NAME, "readChangeType", e);
        }
      }
      logToRejectWriter(lines, message);
      throw new LDIFException(msgID, message, lastEntryLineNumber, true);
    }
@@ -915,7 +724,7 @@
    } else
    {
      // Remove the line
      StringBuilder ln = lines.remove();
      lines.remove();
    }
@@ -957,28 +766,7 @@
        int    msgID   = MSGID_LDIF_COULD_NOT_BASE64_DECODE_DN;
        String message = getMessage(msgID, lastEntryLineNumber, line,
                                    String.valueOf(e));
        BufferedWriter rejectWriter = importConfig.getRejectWriter();
        if (rejectWriter != null)
        {
          try
          {
            rejectWriter.write("# " + message);
            rejectWriter.newLine();
            for (StringBuilder sb : lines)
            {
              rejectWriter.write(sb.toString());
              rejectWriter.newLine();
            }
            rejectWriter.newLine();
          }
          catch (Exception e2)
          {
            assert debugException(CLASS_NAME, "readChangeType", e2);
          }
        }
        logToRejectWriter(lines, message);
        throw new LDIFException(msgID, message, lastEntryLineNumber, true, e);
      }
@@ -1027,270 +815,24 @@
       HashMap<AttributeType,List<Attribute>> operationalAttributes)
          throws LDIFException
  {
    assert debugEnter(CLASS_NAME, "readAttribute", String.valueOf(line),
                        String.valueOf(entryDN), String.valueOf(objectClasses),
                        String.valueOf(userAttributes),
                        String.valueOf(operationalAttributes));
    assert debugEnter(CLASS_NAME, "readAttribute",
        String.valueOf(line),
        String.valueOf(entryDN),
        String.valueOf(objectClasses),
        String.valueOf(userAttributes),
        String.valueOf(operationalAttributes));
    int colonPos = line.indexOf(":");
    if (colonPos <= 0)
    {
      int    msgID   = MSGID_LDIF_NO_ATTR_NAME;
      String message = getMessage(msgID, lastEntryLineNumber, line.toString());
      BufferedWriter rejectWriter = importConfig.getRejectWriter();
      if (rejectWriter != null)
      {
        try
        {
          rejectWriter.write("# " + message);
          rejectWriter.newLine();
          for (StringBuilder sb : lines)
          {
            rejectWriter.write(sb.toString());
            rejectWriter.newLine();
          }
          rejectWriter.newLine();
        }
        catch (Exception e)
        {
          assert debugException(CLASS_NAME, "readAttribute", e);
        }
      }
      throw new LDIFException(msgID, message, lastEntryLineNumber, true);
    }
    LinkedHashSet<String> options;
    String attrName = line.substring(0, colonPos);
    int semicolonPos = attrName.indexOf(';');
    if (semicolonPos > 0)
    {
      options = new LinkedHashSet<String>();
      int nextPos = attrName.indexOf(';', semicolonPos+1);
      while (nextPos > 0)
      {
        String option = attrName.substring(semicolonPos+1, nextPos);
        if (option.length() > 0)
        {
          options.add(option);
          semicolonPos = nextPos;
          nextPos = attrName.indexOf(';', semicolonPos+1);
        }
      }
      String option = attrName.substring(semicolonPos+1);
      if (option.length() > 0)
      {
        options.add(option);
      }
      attrName = attrName.substring(0, attrName.indexOf(';'));
    }
    else
    {
      options   = null;
    }
    // Parse the attribute type description.
    int colonPos = parseColonPosition(lines, line);
    String attrDescr = line.substring(0, colonPos);
    Attribute attribute = parseAttrDescription(attrDescr);
    String attrName = attribute.getName();
    String lowerName = toLowerCase(attrName);
    LinkedHashSet<String> options = attribute.getOptions();
    // Look at the character immediately after the colon.  If there is none,
    // then assume an attribute with an empty value.  If it is another colon,
    // then the value must be base64-encoded.  If it is a less-than sign, then
    // assume that it is a URL.  Otherwise, it is a regular value.
    int length = line.length();
    ASN1OctetString value;
    if (colonPos == (length-1))
    {
      value = new ASN1OctetString();
    }
    else
    {
      char c = line.charAt(colonPos+1);
      if (c == ':')
      {
        // The value is base64-encoded.  Find the first non-blank character,
        // take the rest of the line, and base64-decode it.
        int pos = colonPos+2;
        while ((pos < length) && (line.charAt(pos) == ' '))
        {
          pos++;
        }
        try
        {
          value = new ASN1OctetString(Base64.decode(line.substring(pos)));
        }
        catch (Exception e)
        {
          // The value did not have a valid base64-encoding.
          assert debugException(CLASS_NAME, "readAttribute", e);
          int    msgID   = MSGID_LDIF_COULD_NOT_BASE64_DECODE_ATTR;
          String message = getMessage(msgID, String.valueOf(entryDN),
                                      lastEntryLineNumber, line,
                                      String.valueOf(e));
          BufferedWriter rejectWriter = importConfig.getRejectWriter();
          if (rejectWriter != null)
          {
            try
            {
              rejectWriter.write("# " + message);
              rejectWriter.newLine();
              for (StringBuilder sb : lines)
              {
                rejectWriter.write(sb.toString());
                rejectWriter.newLine();
              }
              rejectWriter.newLine();
            }
            catch (Exception e2)
            {
              assert debugException(CLASS_NAME, "readAttribute", e2);
            }
          }
          throw new LDIFException(msgID, message, lastEntryLineNumber, true, e);
        }
      }
      else if (c == '<')
      {
        // Find the first non-blank character, decode the rest of the line as a
        // URL, and read its contents.
        int pos = colonPos+2;
        while ((pos < length) && (line.charAt(pos) == ' '))
        {
          pos++;
        }
        URL contentURL;
        try
        {
          contentURL = new URL(line.substring(pos));
        }
        catch (Exception e)
        {
          // The URL was malformed or had an invalid protocol.
          assert debugException(CLASS_NAME, "readAttribute", e);
          int    msgID   = MSGID_LDIF_INVALID_URL;
          String message = getMessage(msgID, String.valueOf(entryDN),
                                      lastEntryLineNumber,
                                      String.valueOf(attrName),
                                      String.valueOf(e));
          BufferedWriter rejectWriter = importConfig.getRejectWriter();
          if (rejectWriter != null)
          {
            try
            {
              rejectWriter.write("# " + message);
              rejectWriter.newLine();
              for (StringBuilder sb : lines)
              {
                rejectWriter.write(sb.toString());
                rejectWriter.newLine();
              }
              rejectWriter.newLine();
            }
            catch (Exception e2)
            {
              assert debugException(CLASS_NAME, "readAttribute", e2);
            }
          }
          throw new LDIFException(msgID, message, lastEntryLineNumber, true, e);
        }
        InputStream inputStream = null;
        ByteArrayOutputStream outputStream = null;
        try
        {
          outputStream = new ByteArrayOutputStream();
          inputStream  = contentURL.openConnection().getInputStream();
          int bytesRead;
          while ((bytesRead = inputStream.read(buffer)) > 0)
          {
            outputStream.write(buffer, 0, bytesRead);
          }
          value = new ASN1OctetString(outputStream.toByteArray());
        }
        catch (Exception e)
        {
          // We were unable to read the contents of that URL for some reason.
          assert debugException(CLASS_NAME, "readAttribute", e);
          int msgID = MSGID_LDIF_URL_IO_ERROR;
          String message = getMessage(msgID, String.valueOf(entryDN),
                                      lastEntryLineNumber,
                                      String.valueOf(attrName),
                                      String.valueOf(contentURL),
                                      String.valueOf(e));
          BufferedWriter rejectWriter = importConfig.getRejectWriter();
          if (rejectWriter != null)
          {
            try
            {
              rejectWriter.write("# " + message);
              rejectWriter.newLine();
              for (StringBuilder sb : lines)
              {
                rejectWriter.write(sb.toString());
                rejectWriter.newLine();
              }
              rejectWriter.newLine();
            }
            catch (Exception e2)
            {
              assert debugException(CLASS_NAME, "readAttribute", e2);
            }
          }
          throw new LDIFException(msgID, message, lastEntryLineNumber, true, e);
        }
        finally
        {
          if (outputStream != null)
          {
            try
            {
              outputStream.close();
            } catch (Exception e) {}
          }
          if (inputStream != null)
          {
            try
            {
              inputStream.close();
            } catch (Exception e) {}
          }
        }
      }
      else
      {
        // The rest of the line should be the value.  Skip over any spaces and
        // take the rest of the line as the value.
        int pos = colonPos+1;
        while ((pos < length) && (line.charAt(pos) == ' '))
        {
          pos++;
        }
        value = new ASN1OctetString(line.substring(pos));
      }
    }
    // Now parse the attribute value.
    ASN1OctetString value = parseSingleValue(lines, line, entryDN,
        colonPos, attrName);
    // See if this is an objectclass or an attribute.  Then get the
    // corresponding definition and add the value to the appropriate hash.
@@ -1348,45 +890,7 @@
      }
      AttributeValue attributeValue;
      try
      {
        attributeValue = new AttributeValue(attrType, value);
      }
      catch (Exception e)
      {
        assert debugException(CLASS_NAME, "readAttribute", e);
        int    msgID   = MSGID_LDIF_INVALID_ATTR_SYNTAX;
        String message = getMessage(msgID, String.valueOf(entryDN),
                                    lastEntryLineNumber, value.stringValue(),
                                    attrName, String.valueOf(e));
        BufferedWriter rejectWriter = importConfig.getRejectWriter();
        if (rejectWriter != null)
        {
          try
          {
            rejectWriter.write("# " + message);
            rejectWriter.newLine();
            for (StringBuilder sb : lines)
            {
              rejectWriter.write(sb.toString());
              rejectWriter.newLine();
            }
            rejectWriter.newLine();
          }
          catch (Exception e2)
          {
            assert debugException(CLASS_NAME, "readAttribute", e2);
          }
        }
        throw new LDIFException(msgID, message, lastEntryLineNumber, true, e);
      }
      AttributeValue attributeValue = new AttributeValue(attrType, value);
      List<Attribute> attrList;
      if (attrType.isOperational())
      {
@@ -1433,28 +937,7 @@
            String message = getMessage(msgID, String.valueOf(entryDN),
                                        lastEntryLineNumber, attrName,
                                        value.stringValue());
            BufferedWriter rejectWriter = importConfig.getRejectWriter();
            if (rejectWriter != null)
            {
              try
              {
                rejectWriter.write("# " + message);
                rejectWriter.newLine();
                for (StringBuilder sb : lines)
                {
                  rejectWriter.write(sb.toString());
                  rejectWriter.newLine();
                }
                rejectWriter.newLine();
              }
              catch (Exception e)
              {
                assert debugException(CLASS_NAME, "readAttribute", e);
              }
            }
            logToRejectWriter(lines, message);
            throw new LDIFException(msgID, message, lastEntryLineNumber, true);
          }
          else if (attrType.isSingleValue() && (! valueSet.isEmpty()))
@@ -1462,28 +945,7 @@
            int    msgID   = MSGID_LDIF_MULTIPLE_VALUES_FOR_SINGLE_VALUED_ATTR;
            String message = getMessage(msgID, String.valueOf(entryDN),
                                        lastEntryLineNumber, attrName);
            BufferedWriter rejectWriter = importConfig.getRejectWriter();
            if (rejectWriter != null)
            {
              try
              {
                rejectWriter.write("# " + message);
                rejectWriter.newLine();
                for (StringBuilder sb : lines)
                {
                  rejectWriter.write(sb.toString());
                  rejectWriter.newLine();
                }
                rejectWriter.newLine();
              }
              catch (Exception e)
              {
                assert debugException(CLASS_NAME, "readAttribute", e);
              }
            }
            logToRejectWriter(lines, message);
            throw new LDIFException(msgID, message, lastEntryLineNumber, true);
          }
          else
@@ -1506,367 +968,6 @@
  }
  /**
   * Decodes the provided line as an LDIF attribute and adds it to the
   * appropriate hash.
   *
   * @param  lines                  The full set of lines that comprise the
   *                                entry (used for writing reject information).
   * @param  line                   The line to decode.
   * @param  entryDN                The DN of the entry being decoded.
   * @param  entryAttributes        The set of attributes decoded so far
   *                                for the current entry.
   *
   * @throws  LDIFException  If a problem occurs while trying to decode the
   *                         attribute contained in the provided entry.
   */
  public void readAttribute(LinkedList<StringBuilder> lines,
       StringBuilder line, DN entryDN,
       HashMap<AttributeType,ArrayList<Attribute>> entryAttributes)
          throws LDIFException
  {
    assert debugEnter(CLASS_NAME, "readAttribute", String.valueOf(line),
                        String.valueOf(entryDN),
                        String.valueOf(entryAttributes));
    int colonPos = line.indexOf(":");
    if (colonPos <= 0)
    {
      int    msgID   = MSGID_LDIF_NO_ATTR_NAME;
      String message = getMessage(msgID, lastEntryLineNumber, line.toString());
      BufferedWriter rejectWriter = importConfig.getRejectWriter();
      if (rejectWriter != null)
      {
        try
        {
          rejectWriter.write("# " + message);
          rejectWriter.newLine();
          for (StringBuilder sb : lines)
          {
            rejectWriter.write(sb.toString());
            rejectWriter.newLine();
          }
          rejectWriter.newLine();
        }
        catch (Exception e)
        {
          assert debugException(CLASS_NAME, "readAttribute", e);
        }
      }
      throw new LDIFException(msgID, message, lastEntryLineNumber, true);
    }
    String attrDescr = line.substring(0, colonPos);
    Attribute attribute = parseAttrDescription(attrDescr);
    String attrName = attribute.getName();
    LinkedHashSet<String> options = attribute.getOptions();
    // Look at the character immediately after the colon.  If there is none,
    // then assume an attribute with an empty value.  If it is another colon,
    // then the value must be base64-encoded.  If it is a less-than sign, then
    // assume that it is a URL.  Otherwise, it is a regular value.
    int length = line.length();
    ASN1OctetString value;
    if (colonPos == (length-1))
    {
      value = new ASN1OctetString();
    }
    else
    {
      char c = line.charAt(colonPos+1);
      if (c == ':')
      {
        // The value is base64-encoded.  Find the first non-blank character,
        // take the rest of the line, and base64-decode it.
        int pos = colonPos+2;
        while ((pos < length) && (line.charAt(pos) == ' '))
        {
          pos++;
        }
        try
        {
          value = new ASN1OctetString(Base64.decode(line.substring(pos)));
        }
        catch (Exception e)
        {
          // The value did not have a valid base64-encoding.
          assert debugException(CLASS_NAME, "readAttribute", e);
          int    msgID   = MSGID_LDIF_COULD_NOT_BASE64_DECODE_ATTR;
          String message = getMessage(msgID, String.valueOf(entryDN),
                                      lastEntryLineNumber, line,
                                      String.valueOf(e));
          BufferedWriter rejectWriter = importConfig.getRejectWriter();
          if (rejectWriter != null)
          {
            try
            {
              rejectWriter.write("# " + message);
              rejectWriter.newLine();
              for (StringBuilder sb : lines)
              {
                rejectWriter.write(sb.toString());
                rejectWriter.newLine();
              }
              rejectWriter.newLine();
            }
            catch (Exception e2)
            {
              assert debugException(CLASS_NAME, "readAttribute", e2);
            }
          }
          throw new LDIFException(msgID, message, lastEntryLineNumber, true, e);
        }
      }
      else if (c == '<')
      {
        // Find the first non-blank character, decode the rest of the line as a
        // URL, and read its contents.
        int pos = colonPos+2;
        while ((pos < length) && (line.charAt(pos) == ' '))
        {
          pos++;
        }
        URL contentURL;
        try
        {
          contentURL = new URL(line.substring(pos));
        }
        catch (Exception e)
        {
          // The URL was malformed or had an invalid protocol.
          assert debugException(CLASS_NAME, "readAttribute", e);
          int    msgID   = MSGID_LDIF_INVALID_URL;
          String message = getMessage(msgID, String.valueOf(entryDN),
                                      lastEntryLineNumber,
                                      String.valueOf(attrName),
                                      String.valueOf(e));
          BufferedWriter rejectWriter = importConfig.getRejectWriter();
          if (rejectWriter != null)
          {
            try
            {
              rejectWriter.write("# " + message);
              rejectWriter.newLine();
              for (StringBuilder sb : lines)
              {
                rejectWriter.write(sb.toString());
                rejectWriter.newLine();
              }
              rejectWriter.newLine();
            }
            catch (Exception e2)
            {
              assert debugException(CLASS_NAME, "readAttribute", e2);
            }
          }
          throw new LDIFException(msgID, message, lastEntryLineNumber, true, e);
        }
        InputStream inputStream = null;
        ByteArrayOutputStream outputStream = null;
        try
        {
          outputStream = new ByteArrayOutputStream();
          inputStream  = contentURL.openConnection().getInputStream();
          int bytesRead;
          while ((bytesRead = inputStream.read(buffer)) > 0)
          {
            outputStream.write(buffer, 0, bytesRead);
          }
          value = new ASN1OctetString(outputStream.toByteArray());
        }
        catch (Exception e)
        {
          // We were unable to read the contents of that URL for some reason.
          assert debugException(CLASS_NAME, "readAttribute", e);
          int msgID = MSGID_LDIF_URL_IO_ERROR;
          String message = getMessage(msgID, String.valueOf(entryDN),
                                      lastEntryLineNumber,
                                      String.valueOf(attrName),
                                      String.valueOf(contentURL),
                                      String.valueOf(e));
          BufferedWriter rejectWriter = importConfig.getRejectWriter();
          if (rejectWriter != null)
          {
            try
            {
              rejectWriter.write("# " + message);
              rejectWriter.newLine();
              for (StringBuilder sb : lines)
              {
                rejectWriter.write(sb.toString());
                rejectWriter.newLine();
              }
              rejectWriter.newLine();
            }
            catch (Exception e2)
            {
              assert debugException(CLASS_NAME, "readAttribute", e2);
            }
          }
          throw new LDIFException(msgID, message, lastEntryLineNumber, true, e);
        }
        finally
        {
          if (outputStream != null)
          {
            try
            {
              outputStream.close();
            } catch (Exception e) {}
          }
          if (inputStream != null)
          {
            try
            {
              inputStream.close();
            } catch (Exception e) {}
          }
        }
      }
      else
      {
        // The rest of the line should be the value.  Skip over any spaces and
        // take the rest of the line as the value.
        int pos = colonPos+1;
        while ((pos < length) && (line.charAt(pos) == ' '))
        {
          pos++;
        }
        value = new ASN1OctetString(line.substring(pos));
      }
    }
    AttributeType attrType = attribute.getAttributeType();
    AttributeValue attributeValue;
    try
    {
      attributeValue = new AttributeValue(attrType, value);
    }
    catch (Exception e)
    {
      assert debugException(CLASS_NAME, "readAttribute", e);
      int    msgID   = MSGID_LDIF_INVALID_ATTR_SYNTAX;
      String message = getMessage(msgID, String.valueOf(entryDN),
                                  lastEntryLineNumber, value.stringValue(),
                                  attrName, String.valueOf(e));
      BufferedWriter rejectWriter = importConfig.getRejectWriter();
      if (rejectWriter != null)
      {
        try
        {
          rejectWriter.write("# " + message);
          rejectWriter.newLine();
          for (StringBuilder sb : lines)
          {
            rejectWriter.write(sb.toString());
            rejectWriter.newLine();
          }
          rejectWriter.newLine();
        }
        catch (Exception e2)
        {
          assert debugException(CLASS_NAME, "readAttribute", e2);
        }
      }
      throw new LDIFException(msgID, message, lastEntryLineNumber, true, e);
    }
    ArrayList<Attribute> attrList;
    attrList = entryAttributes.get(attrType);
    if (attrList == null)
    {
      attribute.getValues().add(attributeValue);
      attrList = new ArrayList<Attribute>();
      attrList.add(attribute);
      entryAttributes.put(attrType, attrList);
      return;
    }
    // Check to see if any of the attributes in the list have the same set of
    // options.  If so, then try to add a value to that attribute.
    for (Attribute a : attrList)
    {
      if (a.optionsEqual(options))
      {
        LinkedHashSet<AttributeValue> valueSet = a.getValues();
        if (valueSet.contains(attributeValue))
        {
          int    msgID   = MSGID_LDIF_DUPLICATE_ATTR;
          String message = getMessage(msgID, String.valueOf(entryDN),
                                      lastEntryLineNumber, attrName,
                                      value.stringValue());
          BufferedWriter rejectWriter = importConfig.getRejectWriter();
          if (rejectWriter != null)
          {
            try
            {
              rejectWriter.write("# " + message);
              rejectWriter.newLine();
              for (StringBuilder sb : lines)
              {
                rejectWriter.write(sb.toString());
                rejectWriter.newLine();
              }
              rejectWriter.newLine();
            }
            catch (Exception e)
            {
              assert debugException(CLASS_NAME, "readAttribute", e);
            }
          }
          throw new LDIFException(msgID, message, lastEntryLineNumber, true);
        }
        else
        {
          valueSet.add(attributeValue);
          return;
        }
      }
    }
    // No set of matching options was found, so create a new one and add it to
    // the list.
    attribute.getValues().add(attributeValue);
    attrList.add(attribute);
    return;
  }
  /**
   * Decodes the provided line as an LDIF attribute and returns the
@@ -1885,295 +986,36 @@
   *                                entry or if the parsed attribute name does
   *                                not match the specified attribute name.
   */
  public Attribute readSingleValueAttribute(
  private Attribute readSingleValueAttribute(
       LinkedList<StringBuilder> lines, StringBuilder line, DN entryDN,
       String attributeName) throws LDIFException
  {
    assert debugEnter(CLASS_NAME, "readAttribute", String.valueOf(lines),
      String.valueOf(line),
                        String.valueOf(entryDN),
                        String.valueOf(attributeName));
    assert debugEnter(CLASS_NAME, "readSingleValueAttribute",
        String.valueOf(lines),
        String.valueOf(line),
        String.valueOf(entryDN),
        String.valueOf(attributeName));
    int colonPos = line.indexOf(":");
    if (colonPos <= 0)
    {
      int    msgID   = MSGID_LDIF_NO_ATTR_NAME;
      String message = getMessage(msgID, lastEntryLineNumber, line.toString());
      BufferedWriter rejectWriter = importConfig.getRejectWriter();
      if (rejectWriter != null)
      {
        try
        {
          rejectWriter.write("# " + message);
          rejectWriter.newLine();
          for (StringBuilder sb : lines)
          {
            rejectWriter.write(sb.toString());
            rejectWriter.newLine();
          }
          rejectWriter.newLine();
        }
        catch (Exception e)
        {
          assert debugException(CLASS_NAME, "readAttribute", e);
        }
      }
      throw new LDIFException(msgID, message, lastEntryLineNumber, true);
    }
    // Parse the attribute type description.
    int colonPos = parseColonPosition(lines, line);
    String attrDescr = line.substring(0, colonPos);
    Attribute attribute = parseAttrDescription(attrDescr);
    String attrName = attribute.getName();
    String lowerName = toLowerCase(attrName);
    if(attributeName != null && !attributeName.toLowerCase().equals(lowerName))
    if(attributeName != null && !toLowerCase(attributeName).equals(lowerName))
    {
      int msgID = MSGID_LDIF_INVALID_CHANGERECORD_ATTRIBUTE;
      String message = getMessage(msgID, lowerName, attributeName);
      throw new LDIFException(msgID, message, lastEntryLineNumber, false);
    }
    // Look at the character immediately after the colon.  If there is none,
    // then assume an attribute with an empty value.  If it is another colon,
    // then the value must be base64-encoded.  If it is a less-than sign, then
    // assume that it is a URL.  Otherwise, it is a regular value.
    int length = line.length();
    ASN1OctetString value;
    if (colonPos == (length-1))
    {
      value = new ASN1OctetString();
    }
    else
    {
      char c = line.charAt(colonPos+1);
      if (c == ':')
      {
        // The value is base64-encoded.  Find the first non-blank character,
        // take the rest of the line, and base64-decode it.
        int pos = colonPos+2;
        while ((pos < length) && (line.charAt(pos) == ' '))
        {
          pos++;
        }
        try
        {
          value = new ASN1OctetString(Base64.decode(line.substring(pos)));
        }
        catch (Exception e)
        {
          // The value did not have a valid base64-encoding.
          assert debugException(CLASS_NAME, "readAttribute", e);
          int    msgID   = MSGID_LDIF_COULD_NOT_BASE64_DECODE_ATTR;
          String message = getMessage(msgID, String.valueOf(entryDN),
                                      lastEntryLineNumber, line,
                                      String.valueOf(e));
          BufferedWriter rejectWriter = importConfig.getRejectWriter();
          if (rejectWriter != null)
          {
            try
            {
              rejectWriter.write("# " + message);
              rejectWriter.newLine();
              for (StringBuilder sb : lines)
              {
                rejectWriter.write(sb.toString());
                rejectWriter.newLine();
              }
              rejectWriter.newLine();
            }
            catch (Exception e2)
            {
              assert debugException(CLASS_NAME, "readAttribute", e2);
            }
          }
          throw new LDIFException(msgID, message, lastEntryLineNumber, true, e);
        }
      }
      else if (c == '<')
      {
        // Find the first non-blank character, decode the rest of the line as a
        // URL, and read its contents.
        int pos = colonPos+2;
        while ((pos < length) && (line.charAt(pos) == ' '))
        {
          pos++;
        }
        URL contentURL;
        try
        {
          contentURL = new URL(line.substring(pos));
        }
        catch (Exception e)
        {
          // The URL was malformed or had an invalid protocol.
          assert debugException(CLASS_NAME, "readAttribute", e);
          int    msgID   = MSGID_LDIF_INVALID_URL;
          String message = getMessage(msgID, String.valueOf(entryDN),
                                      lastEntryLineNumber,
                                      String.valueOf(attrName),
                                      String.valueOf(e));
          BufferedWriter rejectWriter = importConfig.getRejectWriter();
          if (rejectWriter != null)
          {
            try
            {
              rejectWriter.write("# " + message);
              rejectWriter.newLine();
              for (StringBuilder sb : lines)
              {
                rejectWriter.write(sb.toString());
                rejectWriter.newLine();
              }
              rejectWriter.newLine();
            }
            catch (Exception e2)
            {
              assert debugException(CLASS_NAME, "readAttribute", e2);
            }
          }
          throw new LDIFException(msgID, message, lastEntryLineNumber, true, e);
        }
        InputStream inputStream = null;
        ByteArrayOutputStream outputStream = null;
        try
        {
          outputStream = new ByteArrayOutputStream();
          inputStream  = contentURL.openConnection().getInputStream();
          int bytesRead;
          while ((bytesRead = inputStream.read(buffer)) > 0)
          {
            outputStream.write(buffer, 0, bytesRead);
          }
          value = new ASN1OctetString(outputStream.toByteArray());
        }
        catch (Exception e)
        {
          // We were unable to read the contents of that URL for some reason.
          assert debugException(CLASS_NAME, "readAttribute", e);
          int msgID = MSGID_LDIF_URL_IO_ERROR;
          String message = getMessage(msgID, String.valueOf(entryDN),
                                      lastEntryLineNumber,
                                      String.valueOf(attrName),
                                      String.valueOf(contentURL),
                                      String.valueOf(e));
          BufferedWriter rejectWriter = importConfig.getRejectWriter();
          if (rejectWriter != null)
          {
            try
            {
              rejectWriter.write("# " + message);
              rejectWriter.newLine();
              for (StringBuilder sb : lines)
              {
                rejectWriter.write(sb.toString());
                rejectWriter.newLine();
              }
              rejectWriter.newLine();
            }
            catch (Exception e2)
            {
              assert debugException(CLASS_NAME, "readAttribute", e2);
            }
          }
          throw new LDIFException(msgID, message, lastEntryLineNumber, true, e);
        }
        finally
        {
          if (outputStream != null)
          {
            try
            {
              outputStream.close();
            } catch (Exception e) {}
          }
          if (inputStream != null)
          {
            try
            {
              inputStream.close();
            } catch (Exception e) {}
          }
        }
      }
      else
      {
        // The rest of the line should be the value.  Skip over any spaces and
        // take the rest of the line as the value.
        int pos = colonPos+1;
        while ((pos < length) && (line.charAt(pos) == ' '))
        {
          pos++;
        }
        value = new ASN1OctetString(line.substring(pos));
      }
    }
    //  Now parse the attribute value.
    ASN1OctetString value = parseSingleValue(lines, line, entryDN,
        colonPos, attrName);
    AttributeType attrType = attribute.getAttributeType();
    AttributeValue attributeValue;
    try
    {
      attributeValue = new AttributeValue(attrType, value);
    }
    catch (Exception e)
    {
      assert debugException(CLASS_NAME, "readAttribute", e);
      int    msgID   = MSGID_LDIF_INVALID_ATTR_SYNTAX;
      String message = getMessage(msgID, String.valueOf(entryDN),
                                  lastEntryLineNumber, value.stringValue(),
                                  attrName, String.valueOf(e));
      BufferedWriter rejectWriter = importConfig.getRejectWriter();
      if (rejectWriter != null)
      {
        try
        {
          rejectWriter.write("# " + message);
          rejectWriter.newLine();
          for (StringBuilder sb : lines)
          {
            rejectWriter.write(sb.toString());
            rejectWriter.newLine();
          }
          rejectWriter.newLine();
        }
        catch (Exception e2)
        {
          assert debugException(CLASS_NAME, "readAttribute", e2);
        }
      }
      throw new LDIFException(msgID, message, lastEntryLineNumber, true, e);
    }
    AttributeValue attributeValue = new AttributeValue(attrType, value);
    attribute.getValues().add(attributeValue);
    return attribute;
@@ -2216,7 +1058,8 @@
    {
      try
      {
        rejectWriter.write("# " + message);
        rejectWriter.write("# ");
        rejectWriter.write(message);
        rejectWriter.newLine();
        for (StringBuilder sb : lastEntryHeaderLines)
@@ -2260,7 +1103,7 @@
   * @return A new attribute with no values, representing the attribute type
   * and its options.
   */
  public static Attribute parseAttrDescription(String attrDescr)
  private static Attribute parseAttrDescription(String attrDescr)
  {
    assert debugEnter(CLASS_NAME, "parseAttributeDescription",
                      String.valueOf(attrDescr));
@@ -2354,5 +1197,551 @@
    return entriesRejected;
  }
  /**
   * Parse a modifyDN change record entry from LDIF.
   *
   * @param entryDN
   *          The name of the entry being modified.
   * @param lines
   *          The lines to parse.
   * @return Returns the parsed modifyDN change record entry.
   * @throws LDIFException
   *           If there was an error when parsing the change record.
   */
  private ChangeRecordEntry parseModifyDNChangeRecordEntry(DN entryDN,
      LinkedList<StringBuilder> lines) throws LDIFException {
    assert debugEnter(CLASS_NAME, "parseModifyDNChangeRecordEntry",
        String.valueOf(entryDN),
        String.valueOf(lines),
        String.valueOf(lineNumber));
    DN newSuperiorDN = null;
    RDN newRDN = null;
    boolean deleteOldRDN = false;
    if(lines.isEmpty())
    {
      int msgID = MSGID_LDIF_NO_MOD_DN_ATTRIBUTES;
      String message = getMessage(msgID);
      throw new LDIFException(msgID, message, lineNumber, true);
    }
    StringBuilder line = lines.remove();
    String rdnStr = getModifyDNAttributeValue(lines, line, entryDN, "newrdn");
    try
    {
      newRDN = RDN.decode(rdnStr);
    } catch (DirectoryException de)
    {
      assert debugException(CLASS_NAME, "parse", de);
      int    msgID   = MSGID_LDIF_INVALID_DN;
      String message = getMessage(msgID, lineNumber, line.toString(),
          de.getErrorMessage());
      throw new LDIFException(msgID, message, lineNumber, true);
    } catch (Exception e)
    {
      assert debugException(CLASS_NAME, "parse", e);
      int    msgID   = MSGID_LDIF_INVALID_DN;
      String message = getMessage(msgID, lineNumber, line.toString(),
          e.getMessage());
      throw new LDIFException(msgID, message, lineNumber, true);
    }
    if(lines.isEmpty())
    {
      int msgID = MSGID_LDIF_NO_DELETE_OLDRDN_ATTRIBUTE;
      String message = getMessage(msgID);
      throw new LDIFException(msgID, message, lineNumber, true);
    }
    lineNumber++;
    line = lines.remove();
    String delStr = getModifyDNAttributeValue(lines, line,
        entryDN, "deleteoldrdn");
    if(delStr.equalsIgnoreCase("false") ||
        delStr.equalsIgnoreCase("no") ||
        delStr.equalsIgnoreCase("0"))
    {
      deleteOldRDN = false;
    } else if(delStr.equalsIgnoreCase("true") ||
        delStr.equalsIgnoreCase("yes") ||
        delStr.equalsIgnoreCase("1"))
    {
      deleteOldRDN = true;
    } else
    {
      int msgID = MSGID_LDIF_INVALID_DELETE_OLDRDN_ATTRIBUTE;
      String message = getMessage(msgID, delStr);
      throw new LDIFException(msgID, message, lineNumber, true);
    }
    if(!lines.isEmpty())
    {
      lineNumber++;
      line = lines.remove();
      String dnStr = getModifyDNAttributeValue(lines, line,
          entryDN, "newsuperior");
      try
      {
        newSuperiorDN = DN.decode(dnStr);
      } catch (DirectoryException de)
      {
        assert debugException(CLASS_NAME, "parse", de);
        int    msgID   = MSGID_LDIF_INVALID_DN;
        String message = getMessage(msgID, lineNumber, line.toString(),
            de.getErrorMessage());
        throw new LDIFException(msgID, message, lineNumber, true);
      } catch (Exception e)
      {
        assert debugException(CLASS_NAME, "parse", e);
        int    msgID   = MSGID_LDIF_INVALID_DN;
        String message = getMessage(msgID, lineNumber, line.toString(),
            e.getMessage());
        throw new LDIFException(msgID, message, lineNumber, true);
      }
    }
    return new ModifyDNChangeRecordEntry(entryDN, newSuperiorDN,
        newRDN, deleteOldRDN);
  }
  /**
   * Return the string value for the specified attribute name which only
   * has one value.
   *
   * @param lines
   *          The set of lines for this change record entry.
   * @param line
   *          The line currently being examined.
   * @param entryDN
   *          The name of the entry being modified.
   * @param attributeName
   *          The attribute name
   * @return the string value for the attribute name.
   * @throws LDIFException
   *           If a problem occurs while attempting to determine the
   *           attribute value.
   */
  private String getModifyDNAttributeValue(LinkedList<StringBuilder> lines,
                                   StringBuilder line,
                                   DN entryDN,
                                   String attributeName) throws LDIFException
  {
    assert debugEnter(CLASS_NAME, "getModifyDNAttributeValue",
        String.valueOf(lines),
        String.valueOf(line),
        String.valueOf(entryDN),
        String.valueOf(attributeName));
    Attribute attr =
      readSingleValueAttribute(lines, line, entryDN, attributeName);
    LinkedHashSet<AttributeValue> values = attr.getValues();
    // Get the attribute value
    Object[] vals = values.toArray();
    return (((AttributeValue)vals[0]).getStringValue());
  }
  /**
   * Parse a modify change record entry from LDIF.
   *
   * @param entryDN
   *          The name of the entry being modified.
   * @param lines
   *          The lines to parse.
   * @return Returns the parsed modify change record entry.
   * @throws LDIFException
   *           If there was an error when parsing the change record.
   */
  private ChangeRecordEntry parseModifyChangeRecordEntry(DN entryDN,
      LinkedList<StringBuilder> lines) throws LDIFException {
    assert debugEnter(CLASS_NAME, "parseModifyChangeRecordEntry",
        String.valueOf(entryDN),
        String.valueOf(lines),
        String.valueOf(lineNumber));
    List<LDAPModification> modifications = new ArrayList<LDAPModification>();
    while(!lines.isEmpty())
    {
      ModificationType modType = null;
      StringBuilder line = lines.remove();
      Attribute attr =
        readSingleValueAttribute(lines, line, entryDN, null);
      String name = attr.getName();
      LinkedHashSet<AttributeValue> values = attr.getValues();
      // Get the attribute description
      String attrDescr = values.iterator().next().getStringValue();
      String lowerName = toLowerCase(name);
      if(lowerName.equals("add"))
      {
        modType = ModificationType.ADD;
      } else if(lowerName.equals("delete"))
      {
        modType = ModificationType.DELETE;
      } else if(lowerName.equals("replace"))
      {
        modType = ModificationType.REPLACE;
      } else if(lowerName.equals("increment"))
      {
        modType = ModificationType.INCREMENT;
      } else
      {
        // Invalid attribute name.
        int msgID = MSGID_LDIF_INVALID_MODIFY_ATTRIBUTE;
        String message = getMessage(msgID, name,
            "add, delete, replace, increment");
        throw new LDIFException(msgID, message, lineNumber, true);
      }
      // Now go through the rest of the attributes till the "-" line is
      // reached.
      Attribute modAttr = LDIFReader.parseAttrDescription(attrDescr);
      while (! lines.isEmpty())
      {
        line = lines.remove();
        if(line.toString().equals("-"))
        {
          break;
        }
        Attribute a =
          readSingleValueAttribute(lines, line, entryDN, attrDescr);
        modAttr.getValues().addAll(a.getValues());
      }
      LDAPAttribute ldapAttr = new LDAPAttribute(modAttr);
      LDAPModification mod = new LDAPModification(modType, ldapAttr);
      modifications.add(mod);
    }
    return new ModifyChangeRecordEntry(entryDN, modifications);
  }
  /**
   * Parse a delete change record entry from LDIF.
   *
   * @param entryDN
   *          The name of the entry being deleted.
   * @param lines
   *          The lines to parse.
   * @return Returns the parsed delete change record entry.
   * @throws LDIFException
   *           If there was an error when parsing the change record.
   */
  private ChangeRecordEntry parseDeleteChangeRecordEntry(DN entryDN,
      LinkedList<StringBuilder> lines) throws LDIFException {
    assert debugEnter(CLASS_NAME, "parseDeleteChangeRecordEntry",
        String.valueOf(entryDN),
        String.valueOf(lines),
        String.valueOf(lineNumber));
    if(!lines.isEmpty())
    {
      int msgID = MSGID_LDIF_INVALID_DELETE_ATTRIBUTES;
      String message = getMessage(msgID);
      throw new LDIFException(msgID, message, lineNumber, true);
    }
    return new DeleteChangeRecordEntry(entryDN);
  }
  /**
   * Parse an add change record entry from LDIF.
   *
   * @param entryDN
   *          The name of the entry being added.
   * @param lines
   *          The lines to parse.
   * @return Returns the parsed add change record entry.
   * @throws LDIFException
   *           If there was an error when parsing the change record.
   */
  private ChangeRecordEntry parseAddChangeRecordEntry(DN entryDN,
      LinkedList<StringBuilder> lines) throws LDIFException {
    assert debugEnter(CLASS_NAME, "parseAddChangeRecordEntry",
        String.valueOf(entryDN),
        String.valueOf(lines),
        String.valueOf(lineNumber));
    HashMap<ObjectClass,String> objectClasses =
      new HashMap<ObjectClass,String>();
    HashMap<AttributeType,List<Attribute>> attributes =
      new HashMap<AttributeType, List<Attribute>>();
    for(StringBuilder line : lines)
    {
      readAttribute(lines, line, entryDN, objectClasses,
          attributes, attributes);
    }
    // Reconstruct the object class attribute.
    AttributeType ocType = DirectoryServer.getObjectClassAttributeType();
    LinkedHashSet<AttributeValue> ocValues =
      new LinkedHashSet<AttributeValue>(objectClasses.size());
    for (String value : objectClasses.values()) {
      AttributeValue av = new AttributeValue(ocType, value);
      ocValues.add(av);
    }
    Attribute ocAttr = new Attribute(ocType, "objectClass", ocValues);
    List<Attribute> ocAttrList = new ArrayList<Attribute>(1);
    ocAttrList.add(ocAttr);
    attributes.put(ocType, ocAttrList);
    return new AddChangeRecordEntry(entryDN, attributes);
  }
  /**
   * Parse colon position in an attribute description.
   *
   * @param lines
   *          The current set of lines.
   * @param line
   *          The current line.
   * @return The colon position.
   * @throws LDIFException
   *           If the colon was badly placed or not found.
   */
  private int parseColonPosition(LinkedList<StringBuilder> lines,
      StringBuilder line) throws LDIFException {
    assert debugEnter(CLASS_NAME, "parseColonPosition",
        String.valueOf(lines),
        String.valueOf(lineNumber));
    int colonPos = line.indexOf(":");
    if (colonPos <= 0)
    {
      int    msgID   = MSGID_LDIF_NO_ATTR_NAME;
      String message = getMessage(msgID, lastEntryLineNumber, line.toString());
      logToRejectWriter(lines, message);
      throw new LDIFException(msgID, message, lastEntryLineNumber, true);
    }
    return colonPos;
  }
  /**
   * Parse a single attribute value from a line of LDIF.
   *
   * @param lines
   *          The current set of lines.
   * @param line
   *          The current line.
   * @param entryDN
   *          The DN of the entry being parsed.
   * @param colonPos
   *          The position of the separator colon in the line.
   * @param attrName
   *          The name of the attribute being parsed.
   * @return The parsed attribute value.
   * @throws LDIFException
   *           If an error occurred when parsing the attribute value.
   */
  private ASN1OctetString parseSingleValue(
      LinkedList<StringBuilder> lines,
      StringBuilder line,
      DN entryDN,
      int colonPos,
      String attrName) throws LDIFException {
    assert debugEnter(CLASS_NAME, "parseSingleValue",
        String.valueOf(lines),
        String.valueOf(line),
        String.valueOf(entryDN),
        String.valueOf(colonPos),
        String.valueOf(attrName));
    // Look at the character immediately after the colon. If there is
    // none, then assume an attribute with an empty value. If it is another
    // colon, then the value must be base64-encoded. If it is a less-than
    // sign, then assume that it is a URL. Otherwise, it is a regular value.
    int length = line.length();
    ASN1OctetString value;
    if (colonPos == (length-1))
    {
      value = new ASN1OctetString();
    }
    else
    {
      char c = line.charAt(colonPos+1);
      if (c == ':')
      {
        // The value is base64-encoded. Find the first non-blank
        // character, take the rest of the line, and base64-decode it.
        int pos = colonPos+2;
        while ((pos < length) && (line.charAt(pos) == ' '))
        {
          pos++;
        }
        try
        {
          value = new ASN1OctetString(Base64.decode(line.substring(pos)));
        }
        catch (Exception e)
        {
          // The value did not have a valid base64-encoding.
          assert debugException(CLASS_NAME, "readAttribute", e);
          int    msgID   = MSGID_LDIF_COULD_NOT_BASE64_DECODE_ATTR;
          String message = getMessage(msgID, String.valueOf(entryDN),
                                      lastEntryLineNumber, line,
                                      String.valueOf(e));
          logToRejectWriter(lines, message);
          throw new LDIFException(msgID, message, lastEntryLineNumber, true, e);
        }
      }
      else if (c == '<')
      {
        // Find the first non-blank character, decode the rest of the
        // line as a URL, and read its contents.
        int pos = colonPos+2;
        while ((pos < length) && (line.charAt(pos) == ' '))
        {
          pos++;
        }
        URL contentURL;
        try
        {
          contentURL = new URL(line.substring(pos));
        }
        catch (Exception e)
        {
          // The URL was malformed or had an invalid protocol.
          assert debugException(CLASS_NAME, "readAttribute", e);
          int    msgID   = MSGID_LDIF_INVALID_URL;
          String message = getMessage(msgID, String.valueOf(entryDN),
                                      lastEntryLineNumber,
                                      String.valueOf(attrName),
                                      String.valueOf(e));
          logToRejectWriter(lines, message);
          throw new LDIFException(msgID, message, lastEntryLineNumber, true, e);
        }
        InputStream inputStream = null;
        ByteArrayOutputStream outputStream = null;
        try
        {
          outputStream = new ByteArrayOutputStream();
          inputStream  = contentURL.openConnection().getInputStream();
          int bytesRead;
          while ((bytesRead = inputStream.read(buffer)) > 0)
          {
            outputStream.write(buffer, 0, bytesRead);
          }
          value = new ASN1OctetString(outputStream.toByteArray());
        }
        catch (Exception e)
        {
          // We were unable to read the contents of that URL for some
          // reason.
          assert debugException(CLASS_NAME, "readAttribute", e);
          int msgID = MSGID_LDIF_URL_IO_ERROR;
          String message = getMessage(msgID, String.valueOf(entryDN),
                                      lastEntryLineNumber,
                                      String.valueOf(attrName),
                                      String.valueOf(contentURL),
                                      String.valueOf(e));
          logToRejectWriter(lines, message);
          throw new LDIFException(msgID, message, lastEntryLineNumber, true, e);
        }
        finally
        {
          if (outputStream != null)
          {
            try
            {
              outputStream.close();
            } catch (Exception e) {}
          }
          if (inputStream != null)
          {
            try
            {
              inputStream.close();
            } catch (Exception e) {}
          }
        }
      }
      else
      {
        // The rest of the line should be the value. Skip over any
        // spaces and take the rest of the line as the value.
        int pos = colonPos+1;
        while ((pos < length) && (line.charAt(pos) == ' '))
        {
          pos++;
        }
        value = new ASN1OctetString(line.substring(pos));
      }
    }
    return value;
  }
  /**
   * Log a message to the reject writer if one is configured.
   *
   * @param lines
   *          The set of rejected lines.
   * @param message
   *          The associated error message.
   */
  private void logToRejectWriter(LinkedList<StringBuilder> lines,
      String message) {
    assert debugEnter(CLASS_NAME, "logToRejectWriter",
        String.valueOf(lines),
        String.valueOf(message));
    BufferedWriter rejectWriter = importConfig.getRejectWriter();
    if (rejectWriter != null)
    {
      try
      {
        rejectWriter.write("# ");
        rejectWriter.write(message);
        rejectWriter.newLine();
        for (StringBuilder sb : lines)
        {
          rejectWriter.write(sb.toString());
          rejectWriter.newLine();
        }
        rejectWriter.newLine();
      }
      catch (Exception e)
      {
        assert debugException(CLASS_NAME, "logToRejectWriter", e);
      }
    }
  }
}
opendj-sdk/opends/src/server/org/opends/server/util/ModifyChangeRecordEntry.java
@@ -28,20 +28,16 @@
import static org.opends.server.loggers.Debug.debugConstructor;
import static org.opends.server.loggers.Debug.debugEnter;
import static org.opends.server.messages.MessageHandler.getMessage;
import static org.opends.server.messages.UtilityMessages.*;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.opends.server.protocols.ldap.LDAPAttribute;
import org.opends.server.protocols.ldap.LDAPModification;
import org.opends.server.types.Attribute;
import org.opends.server.types.AttributeValue;
import org.opends.server.types.DN;
import org.opends.server.types.ModificationType;
@@ -59,38 +55,47 @@
      "org.opends.server.util.ModifyChangeRecordEntry";
  private LDIFReader reader;
  /**
   * The modifications for this change record.
   */
  private final List<LDAPModification> modifications;
  private ArrayList<LDAPModification> modifications =
      new ArrayList<LDAPModification>();
  /**
   * Creates a new entry with the provided information.
   *
   * @param  dn      The distinguished name for this entry.
   * @param  reader  The LDIFReader instance used to read the entries.
   * @param modifications The modifications for this change record.
   */
  public ModifyChangeRecordEntry(DN dn, LDIFReader reader)
  public ModifyChangeRecordEntry(DN dn,
      Collection<LDAPModification> modifications)
  {
    super(dn, reader);
    super(dn);
    this.reader = reader;
    assert debugConstructor(CLASS_NAME, String.valueOf(dn),
        String.valueOf(modifications));
    this.modifications = new ArrayList<LDAPModification>(modifications);
  }
  /**
   * Get the list of modifications from the attributes.
   * Get the list of modifications.
   * <p>
   * The returned list is read-only.
   *
   * @return the list of modifications.
   * @return Returns the unmodifiable list of modifications.
   */
  public ArrayList<LDAPModification> getModifications()
  public List<LDAPModification> getModifications()
  {
    assert debugEnter(CLASS_NAME, "getModifications");
    return modifications;
    return Collections.unmodifiableList(modifications);
  }
  /**
   * Retrieves the name of the change operation type.
   *
@@ -102,84 +107,5 @@
    return ChangeOperationType.MODIFY;
  }
  /**
   * Parse the lines and populate the internal structures.
   *
   * @param lines         The lines to parse.
   * @param lineNumber    The current line number.
   *
   * @exception LDIFException if there is an error during parsing.
   */
  public void parse(LinkedList<StringBuilder> lines, long lineNumber)
      throws LDIFException
  {
    assert debugEnter(CLASS_NAME, "parse", String.valueOf(lines),
          String.valueOf(lineNumber));
    while(!lines.isEmpty())
    {
      ModificationType modType = null;
      StringBuilder line = lines.remove();
      Attribute attr =
           reader.readSingleValueAttribute(lines, line, getDN(), null);
      String name = attr.getName();
      LinkedHashSet<AttributeValue> values = attr.getValues();
      // Only 1 entry should be present
      if(values.size() != 1)
      {
          int msgID = MSGID_LDIF_INVALID_MODIFY_ATTRIBUTE_VAL;
          String message = getMessage(msgID, name);
          throw new LDIFException(msgID, message, lineNumber, true);
      }
      // Get the attribute description
      String attrDescr = values.iterator().next().getStringValue();
      String lowerName = name.toLowerCase();
      if(lowerName.equals("add"))
      {
        modType = ModificationType.ADD;
      } else if(lowerName.equals("delete"))
      {
        modType = ModificationType.DELETE;
      } else if(lowerName.equals("replace"))
      {
        modType = ModificationType.REPLACE;
      } else if(lowerName.equals("increment"))
      {
        modType = ModificationType.INCREMENT;
      } else
      {
        // Invalid attribute name.
        int msgID = MSGID_LDIF_INVALID_MODIFY_ATTRIBUTE;
        String message = getMessage(msgID, name,
              "add, delete, replace, increment");
        throw new LDIFException(msgID, message, lineNumber, true);
      }
      // Now go through the rest of the attributes till the "-" line is reached.
      Attribute modAttr = LDIFReader.parseAttrDescription(attrDescr);
      while (! lines.isEmpty())
      {
        line = lines.remove();
        if(line.toString().equals("-"))
        {
          break;
        }
        Attribute a =
             reader.readSingleValueAttribute(lines, line, getDN(), attrDescr);
        modAttr.getValues().addAll(a.getValues());
      }
      LDAPAttribute ldapAttr = new LDAPAttribute(modAttr);
      LDAPModification mod = new LDAPModification(modType, ldapAttr);
      modifications.add(mod);
    }
  }
}
opendj-sdk/opends/src/server/org/opends/server/util/ModifyDNChangeRecordEntry.java
@@ -30,16 +30,7 @@
import static org.opends.server.loggers.Debug.debugConstructor;
import static org.opends.server.loggers.Debug.debugEnter;
import static org.opends.server.loggers.Debug.debugException;
import static org.opends.server.messages.MessageHandler.getMessage;
import static org.opends.server.messages.UtilityMessages.*;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import org.opends.server.core.DirectoryException;
import org.opends.server.types.Attribute;
import org.opends.server.types.AttributeValue;
import org.opends.server.types.DN;
import org.opends.server.types.RDN;
@@ -58,32 +49,40 @@
  private static final String CLASS_NAME =
      "org.opends.server.util.ModifyDNChangeRecordEntry";
  private LDIFReader reader;
  // The new RDN.
  private RDN newRDN = null;
  private final RDN newRDN;
  // The new superior DN.
  private DN newSuperiorDN = null;
  private final DN newSuperiorDN;
  // Delete the old RDN?
  private boolean deleteOldRDN = false;
  private final boolean deleteOldRDN;
  /**
   * Creates a new entry with the provided information.
   *
   * @param  dn      The distinguished name for this entry.
   * @param  reader  The LDIFReader instance used to read the entries.
   * @param dn
   *          The distinguished name for this entry.
   * @param newSuperiorDN
   *          The new superior DN.
   * @param newRDN
   *          The new RDN.
   * @param deleteOldRDN
   *          Delete the old RDN?
   */
  public ModifyDNChangeRecordEntry(DN dn, LDIFReader reader)
  public ModifyDNChangeRecordEntry(DN dn, DN newSuperiorDN,
      RDN newRDN, boolean deleteOldRDN)
  {
    super(dn, reader);
    super(dn);
    assert debugConstructor(CLASS_NAME, String.valueOf(dn),
                            String.valueOf(reader));
                            String.valueOf(newSuperiorDN),
                            String.valueOf(newRDN),
                            String.valueOf(deleteOldRDN));
    this.reader = reader;
    this.newSuperiorDN = newSuperiorDN;
    this.newRDN = newRDN;
    this.deleteOldRDN = deleteOldRDN;
  }
@@ -137,147 +136,5 @@
    return ChangeOperationType.MODIFY_DN;
  }
  /**
   * Parse the lines and populate the internal structures.
   *
   * @param lines        The lines to parse.
   * @param lineNumber   The current line number.
   *
   * @exception LDIFException if there is an error during parsing.
   */
  public void parse(LinkedList<StringBuilder> lines, long lineNumber)
         throws LDIFException
  {
    assert debugEnter(CLASS_NAME, "parse", String.valueOf(lines),
                      String.valueOf(lineNumber));
    if(lines.isEmpty())
    {
      int msgID = MSGID_LDIF_NO_MOD_DN_ATTRIBUTES;
      String message = getMessage(msgID);
      throw new LDIFException(msgID, message, lineNumber, true);
    }
    StringBuilder line = lines.remove();
    String rdnStr = getAttributeValue(lines, line, "newrdn");
    try
    {
      newRDN = RDN.decode(rdnStr);
    } catch (DirectoryException de)
    {
      assert debugException(CLASS_NAME, "parse", de);
      int    msgID   = MSGID_LDIF_INVALID_DN;
      String message = getMessage(msgID, lineNumber, line.toString(),
                                  de.getErrorMessage());
      throw new LDIFException(msgID, message, lineNumber, true);
    } catch (Exception e)
    {
      assert debugException(CLASS_NAME, "parse", e);
      int    msgID   = MSGID_LDIF_INVALID_DN;
      String message = getMessage(msgID, lineNumber, line.toString(),
                                  e.getMessage());
      throw new LDIFException(msgID, message, lineNumber, true);
    }
    if(lines.isEmpty())
    {
      int msgID = MSGID_LDIF_NO_DELETE_OLDRDN_ATTRIBUTE;
      String message = getMessage(msgID);
      throw new LDIFException(msgID, message, lineNumber, true);
    }
    lineNumber++;
    line = lines.remove();
    String delStr = getAttributeValue(lines, line, "deleteoldrdn");
    if(delStr.equalsIgnoreCase("false") ||
    delStr.equalsIgnoreCase("no") ||
    delStr.equalsIgnoreCase("0"))
    {
      deleteOldRDN = false;
    } else if(delStr.equalsIgnoreCase("true") ||
        delStr.equalsIgnoreCase("yes") ||
        delStr.equalsIgnoreCase("1"))
    {
      deleteOldRDN = true;
    } else
    {
      int msgID = MSGID_LDIF_INVALID_DELETE_OLDRDN_ATTRIBUTE;
      String message = getMessage(msgID, delStr);
      throw new LDIFException(msgID, message, lineNumber, true);
    }
    if(!lines.isEmpty())
    {
      lineNumber++;
      line = lines.remove();
      String dnStr = getAttributeValue(lines, line, "newsuperior");
      try
      {
        newSuperiorDN = DN.decode(dnStr);
      } catch (DirectoryException de)
      {
        assert debugException(CLASS_NAME, "parse", de);
        int    msgID   = MSGID_LDIF_INVALID_DN;
        String message = getMessage(msgID, lineNumber, line.toString(),
                                    de.getErrorMessage());
        throw new LDIFException(msgID, message, lineNumber, true);
      } catch (Exception e)
      {
        assert debugException(CLASS_NAME, "parse", e);
        int    msgID   = MSGID_LDIF_INVALID_DN;
        String message = getMessage(msgID, lineNumber, line.toString(),
                                    e.getMessage());
        throw new LDIFException(msgID, message, lineNumber, true);
      }
    }
  }
  /**
   * Return the string value for the specified attribute name which
   * only has one value.
   *
   * @param  lines          The set of lines for this change record entry.
   * @param  line           The line currently being examined.
   * @param  attributeName  The attribute name
   *
   * @return the string value for the attribute name.
   *
   * @throws  LDIFException  If a problem occurs while attempting to determine
   *                         the attribute value.
   */
  private String getAttributeValue(LinkedList<StringBuilder> lines,
                                   StringBuilder line,
                                   String attributeName) throws LDIFException
  {
    assert debugEnter(CLASS_NAME, "getAttributeValue", String.valueOf(lines),
                      String.valueOf(line), String.valueOf(attributeName));
    Attribute attr =
      reader.readSingleValueAttribute(lines, line, getDN(), attributeName);
    LinkedHashSet<AttributeValue> values = attr.getValues();
    // Only 1 entry should be present
    if(values.size() != 1)
    {
      int msgID = MSGID_LDIF_INVALID_MODIFY_ATTRIBUTE_VAL;
      String message = getMessage(msgID, attributeName);
      throw new LDIFException(msgID, message);
    }
    // Get the attribute value
    Object[] vals = values.toArray();
    return (((AttributeValue)vals[0]).getStringValue());
  }
}
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/util/TestAddChangeRecordEntry.java
@@ -26,12 +26,16 @@
 */
package org.opends.server.util;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.opends.server.TestCaseUtils;
import org.opends.server.types.Attribute;
import org.opends.server.types.AttributeType;
import org.opends.server.types.DN;
import org.opends.server.types.LDIFImportConfig;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
@@ -45,8 +49,11 @@
 * been overridden.
 */
public final class TestAddChangeRecordEntry extends UtilTestCase {
  // An empty LDIF reader.
  private LDIFReader emptyReader;
  // Set of attributes.
  private Map<AttributeType, List<Attribute>> attributes;
  // The attribute being added.
  private Attribute attribute;
  /**
   * Once-only initialization.
@@ -60,9 +67,11 @@
    // start the server.
    TestCaseUtils.startServer();
    InputStream stream = new ByteArrayInputStream(new byte[0]);
    LDIFImportConfig config = new LDIFImportConfig(stream);
    emptyReader = new LDIFReader(config);
    attributes = new HashMap<AttributeType, List<Attribute>>();
    attribute = new Attribute("cn", "hello world");
    ArrayList<Attribute> alist = new ArrayList<Attribute>(1);
    alist.add(attribute);
    attributes.put(attribute.getAttributeType(), alist);
  }
  /**
@@ -73,7 +82,7 @@
   */
  @Test
  public void testConstructorNullDN() throws Exception {
    AddChangeRecordEntry entry = new AddChangeRecordEntry(null, emptyReader);
    AddChangeRecordEntry entry = new AddChangeRecordEntry(null, attributes);
    Assert.assertEquals(entry.getDN(), new DN());
  }
@@ -87,7 +96,7 @@
  @Test
  public void testConstructorEmptyDN() throws Exception {
    AddChangeRecordEntry entry = new AddChangeRecordEntry(new DN(),
        emptyReader);
        attributes);
    Assert.assertEquals(entry.getDN(), new DN());
  }
@@ -104,7 +113,7 @@
    DN testDN2 = DN.decode("dc=hello, dc=world");
    AddChangeRecordEntry entry = new AddChangeRecordEntry(testDN1,
        emptyReader);
        attributes);
    Assert.assertEquals(entry.getDN(), testDN2);
  }
@@ -117,28 +126,41 @@
   */
  @Test
  public void testChangeOperationType() throws Exception {
    AddChangeRecordEntry entry = new AddChangeRecordEntry(null, emptyReader);
    AddChangeRecordEntry entry = new AddChangeRecordEntry(null, attributes);
    Assert.assertEquals(entry.getChangeOperationType(),
        ChangeOperationType.ADD);
  }
  /**
   * Tests parse and getAttributes methods.
   * <p>
   * Due to tight coupling between the
   * {@link AddChangeRecordEntry#parse(java.util.LinkedList, long)}
   * method and the {@link LDIFReader} class it is not easy to test the
   * {@link AddChangeRecordEntry#getAttributes()} method. Instead, we'll
   * test that in the {@link LDIFReader} test suite.
   * Tests getAttributes method for empty modifications.
   * 
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test(enabled = false)
  public void testGetAttributes() throws Exception {
    // FIXME: fix tight-coupling between parse() and LDIFReader.
    Assert.assertTrue(false);
  @Test
  public void testGetAttributesEmpty() throws Exception {
    Map<AttributeType, List<Attribute>> empty = Collections.emptyMap();
    AddChangeRecordEntry entry = new AddChangeRecordEntry(null, empty);
    List<Attribute> attrs = entry.getAttributes();
    Assert.assertEquals(attrs.size(), 0);
  }
  /**
   * Tests getAttributes method for non-empty modifications.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testGetAttributesNonEmpty() throws Exception {
    AddChangeRecordEntry entry = new AddChangeRecordEntry(null, attributes);
    List<Attribute> attrs = entry.getAttributes();
    Assert.assertEquals(attrs.size(), 1);
    Attribute first = attrs.get(0);
    Assert.assertEquals(first, attribute);
  }
}
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/util/TestChangeRecordEntry.java
@@ -26,8 +26,6 @@
 */
package org.opends.server.util;
import java.util.LinkedList;
import org.opends.server.TestCaseUtils;
import org.opends.server.types.DN;
import org.testng.Assert;
@@ -65,15 +63,6 @@
      // Will not use.
      return null;
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public void parse(LinkedList<StringBuilder> lines, long lineNumber)
        throws LDIFException {
      // Will not use.
    }
  }
  /**
@@ -88,7 +77,7 @@
    // start the server.
    TestCaseUtils.startServer();
  }
  /**
   * Tests the constructor with null DN.
   * 
@@ -130,23 +119,4 @@
    Assert.assertEquals(entry.getDN(), testDN2);
  }
  /**
   * Tests the set DN method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test(dependsOnMethods = { "testConstructorNonNullDN" })
  public void testSetDN() throws Exception {
    DN testDN1 = DN.decode("dc=hello, dc=world");
    DN testDN2 = DN.decode("dc=goodbye, dc=world");
    DN testDN3 = DN.decode("dc=goodbye, dc=world");
    MyChangeRecordEntry entry = new MyChangeRecordEntry(testDN1);
    entry.setDN(testDN2);
    Assert.assertEquals(entry.getDN(), testDN3);
  }
}
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/util/TestDeleteChangeRecordEntry.java
@@ -26,12 +26,8 @@
 */
package org.opends.server.util;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import org.opends.server.TestCaseUtils;
import org.opends.server.types.DN;
import org.opends.server.types.LDIFImportConfig;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
@@ -45,9 +41,6 @@
 * been overridden.
 */
public final class TestDeleteChangeRecordEntry extends UtilTestCase {
  // An empty LDIF reader.
  private LDIFReader emptyReader;
  /**
   * Once-only initialization.
   * 
@@ -59,10 +52,6 @@
    // This test suite depends on having the schema available, so we'll
    // start the server.
    TestCaseUtils.startServer();
    InputStream stream = new ByteArrayInputStream(new byte[0]);
    LDIFImportConfig config = new LDIFImportConfig(stream);
    emptyReader = new LDIFReader(config);
  }
  /**
@@ -73,8 +62,7 @@
   */
  @Test
  public void testConstructorNullDN() throws Exception {
    DeleteChangeRecordEntry entry = new DeleteChangeRecordEntry(null,
        emptyReader);
    DeleteChangeRecordEntry entry = new DeleteChangeRecordEntry(null);
    Assert.assertEquals(entry.getDN(), new DN());
  }
@@ -87,8 +75,7 @@
   */
  @Test
  public void testConstructorEmptyDN() throws Exception {
    DeleteChangeRecordEntry entry = new DeleteChangeRecordEntry(new DN(),
        emptyReader);
    DeleteChangeRecordEntry entry = new DeleteChangeRecordEntry(new DN());
    Assert.assertEquals(entry.getDN(), new DN());
  }
@@ -104,8 +91,7 @@
    DN testDN1 = DN.decode("dc=hello, dc=world");
    DN testDN2 = DN.decode("dc=hello, dc=world");
    DeleteChangeRecordEntry entry = new DeleteChangeRecordEntry(testDN1,
        emptyReader);
    DeleteChangeRecordEntry entry = new DeleteChangeRecordEntry(testDN1);
    Assert.assertEquals(entry.getDN(), testDN2);
  }
@@ -118,28 +104,10 @@
   */
  @Test
  public void testChangeOperationType() throws Exception {
    DeleteChangeRecordEntry entry = new DeleteChangeRecordEntry(null,
        emptyReader);
    DeleteChangeRecordEntry entry = new DeleteChangeRecordEntry(null);
    Assert.assertEquals(entry.getChangeOperationType(),
        ChangeOperationType.DELETE);
  }
  /**
   * Tests parse method.
   * <p>
   * Due to tight coupling between the
   * {@link DeleteChangeRecordEntry#parse(java.util.LinkedList, long)}
   * method and the {@link LDIFReader} class we'll test this method in
   * the {@link LDIFReader} test suite.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test(enabled = false)
  public void testParse() throws Exception {
    // FIXME: fix tight-coupling between parse() and LDIFReader.
    Assert.assertTrue(false);
  }
}
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/util/TestLDIFReader.java
New file
@@ -0,0 +1,980 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * 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/opends/resource/legal-notices/OpenDS.LICENSE.  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
 *
 *
 *      Portions Copyright 2006 Sun Microsystems, Inc.
 */
package org.opends.server.util;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import org.opends.server.TestCaseUtils;
import org.opends.server.core.DirectoryServer;
import org.opends.server.protocols.ldap.LDAPModification;
import org.opends.server.types.Attribute;
import org.opends.server.types.AttributeType;
import org.opends.server.types.AttributeValue;
import org.opends.server.types.DN;
import org.opends.server.types.Entry;
import org.opends.server.types.LDIFImportConfig;
import org.opends.server.types.Modification;
import org.opends.server.types.ModificationType;
import org.opends.server.types.ObjectClass;
import org.opends.server.types.RDN;
import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
/**
 * This class defines a set of tests for the
 * {@link org.opends.server.util.LDIFReader} class.
 */
public final class TestLDIFReader extends UtilTestCase {
  // Top object class.
  private ObjectClass OC_TOP;
  // Person object class.
  private ObjectClass OC_PERSON;
  // Object class attribute type.
  private AttributeType AT_OC;
  // Common name attribute type.
  private AttributeType AT_CN;
  // Surname attribute type.
  private AttributeType AT_SN;
  // Description attribute type.
  private AttributeType AT_DESCR;
  // Telephone number attribute type.
  private AttributeType AT_TELN;
  // Temporary file containing an attribute value.
  private File TEMP_FILE = null;
  // Temporary file content.
  private static final String TEMP_FILE_STRING = "hello world";
  // Temporary file LDIF.
  private static final String TEMP_FILE_LDIF = "dn: cn=john smith, dc=com\n"
      + "changetype: add\n" + "objectClass: top\n"
      + "objectClass: person\n" + "cn: john\n" + "sn: smith\n"
      + "description:< file:///";
  /**
   * String of valid LDIF change records.
   *
   * Take from example 6 in the LDIF RFC + a couple of additions.
   */
  private static final String VALID_LDIF = "version: 1\n"
      + "# Add a new entry\n"
      + "dn: cn=Fiona Jensen, ou=Marketing, dc=airius, dc=com\n"
      + "changetype: add\n"
      + "objectclass: top\n"
      + "objectclass: person\n"
      + "objectclass: organizationalPerson\n"
      + "cn: Fiona Jensen\n"
      + "sn: Jensen\n"
      + "uid: fiona\n"
      + "telephonenumber: +1 408 555 1212\n"
      + "\n"
      + "# Delete an existing entry\n"
      + "dn: cn=Robert Jensen, ou=Marketing, dc=airius, dc=com\n"
      + "changetype: delete\n"
      + "\n"
      + "# Modify an entry's relative distinguished name\n"
      + "dn: cn=Paul Jensen, ou=Product Development, dc=airius, dc=com\n"
      + "changetype: modrdn\n"
      + "newrdn: cn=Paula Jensen\n"
      + "deleteoldrdn: 1\n"
      + "\n"
      + "# Rename an entry and move all of its children to a new location in\n"
      + "# the directory tree (only implemented by LDAPv3 servers).\n"
      + "dn: ou=PD Accountants, ou=Product Development, dc=airius, dc=com\n"
      + "changetype: modrdn\n"
      + "newrdn: ou=Product Development Accountants\n"
      + "deleteoldrdn: 0\n"
      + "newsuperior: ou=Accounting, dc=airius, dc=com\n"
      + "\n"
      + "# Modify an entry: add an additional value to the postaladdress\n"
      + "# attribute, completely delete the description attribute, replace\n"
      + "# the telephonenumber attribute with two values, and delete a specific\n"
      + "# value from the facsimiletelephonenumber attribute\n"
      + "dn: cn=Paula Jensen, ou=Product Development, dc=airius, dc=com\n"
      + "changetype: modify\n"
      + "add: postaladdress\n"
      + "postaladdress: 123 Anystreet $ Sunnyvale, CA $ 94086\n"
      + "-\n"
      + "delete: description\n"
      + "-\n"
      + "replace: telephonenumber\n"
      + "telephonenumber: +1 408 555 1234\n"
      + "telephonenumber: +1 408 555 5678\n"
      + "-\n"
      + "delete: facsimiletelephonenumber\n"
      + "facsimiletelephonenumber: +1 408 555 9876\n"
      + "-\n"
      + "\n"
      + "# Modify an entry: replace the postaladdress attribute with an empty\n"
      + "# set of values (which will cause the attribute to be removed), and\n"
      + "# delete the entire description attribute. Note that the first will\n"
      + "# always succeed, while the second will only succeed if at least\n"
      + "# one value for the description attribute is present.\n"
      + "dn: cn=Ingrid Jensen, ou=Product Support, dc=airius, dc=com\n"
      + "changetype: modify\n"
      + "replace: postaladdress\n"
      + "-\n"
      + "delete: description\n"
      + "-\n"
      + "\n"
      + "# Modify rootDSE.\n"
      + "dn: \n"
      + "changetype: modify\n"
      + "delete: description\n"
      + "-\n"
      + "\n"
      + "# Modify base64 DN.\n"
      + "dn:: dWlkPXJvZ2FzYXdhcmEsb3U95Za25qWt6YOoLG89QWlyaXVz\n"
      + "# dn:: uid=<uid>,ou=<JapaneseOU>,o=Airius\n"
      + "changetype:: bW9kaWZ5\n"
      + "delete: description\n"
      + "-\n"
      + "\n";
  /**
   * Once-only initialization.
   *
   * @throws Exception
   *           If an unexpected error occurred.
   */
  @BeforeClass
  public void setUp() throws Exception {
    // This test suite depends on having the schema available, so we'll
    // start the server.
    TestCaseUtils.startServer();
    // Initialize schema bits.
    OC_TOP = DirectoryServer.getObjectClass("top");
    OC_PERSON = DirectoryServer.getObjectClass("person");
    AT_OC = DirectoryServer.getObjectClassAttributeType();
    AT_CN = DirectoryServer.getAttributeType("cn");
    AT_SN = DirectoryServer.getAttributeType("sn");
    AT_DESCR = DirectoryServer.getAttributeType("description");
    AT_TELN = DirectoryServer.getAttributeType("telephonenumber");
    // Create a temporary file containing an attribute value.
    TEMP_FILE = File.createTempFile("tmp", "txt");
    OutputStream out = null;
    try {
      out = new FileOutputStream(TEMP_FILE);
      out.write(TEMP_FILE_STRING.getBytes("UTF-8"));
    } finally {
      if (out != null) {
        out.close();
      }
    }
  }
  /**
   * Once-only tear-down.
   *
   * @throws Exception
   *           If an unexpected error occurred.
   */
  @AfterClass
  public void tearDown() throws Exception {
    if (TEMP_FILE != null) {
      TEMP_FILE.delete();
    }
  }
  /**
   * Check the initial state of an LDIF reader.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testInitialState() throws Exception {
    LDIFReader reader = createLDIFReader("");
    try {
      Assert.assertEquals(reader.getEntriesIgnored(), 0);
      Assert.assertEquals(reader.getEntriesRead(), 0);
      Assert.assertEquals(reader.getEntriesRejected(), 0);
      Assert.assertEquals(reader.getLastEntryLineNumber(), -1);
    } finally {
      reader.close();
    }
  }
  /**
   * Attempt to read an entry from an empty LDIF stream.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testReadEntryEmptyStream() throws Exception {
    LDIFReader reader = createLDIFReader("");
    try {
      Entry entry = reader.readEntry();
      Assert.assertNull(entry);
      Assert.assertEquals(reader.getEntriesIgnored(), 0);
      Assert.assertEquals(reader.getEntriesRead(), 0);
      Assert.assertEquals(reader.getEntriesRejected(), 0);
      Assert.assertEquals(reader.getLastEntryLineNumber(), -1);
    } finally {
      reader.close();
    }
  }
  /**
   * Attempt to read an entry from an empty LDIF stream containing just
   * the LDIF version.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test(dependsOnMethods = { "testReadEntryEmptyStream" })
  public void testReadEntryEmptyStreamVersion() throws Exception {
    LDIFReader reader = createLDIFReader("version: 1\n");
    try {
      Entry entry = reader.readEntry();
      Assert.assertNull(entry);
      Assert.assertEquals(reader.getEntriesIgnored(), 0);
      Assert.assertEquals(reader.getEntriesRead(), 0);
      Assert.assertEquals(reader.getEntriesRejected(), 0);
      Assert.assertEquals(reader.getLastEntryLineNumber(), 1);
    } finally {
      reader.close();
    }
  }
  /**
   * Attempt to read a change record from an empty LDIF stream.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testChangeRecordEmptyStream() throws Exception {
    LDIFReader reader = createLDIFReader("");
    try {
      ChangeRecordEntry change = reader.readChangeRecord(true);
      Assert.assertNull(change);
      Assert.assertEquals(reader.getEntriesIgnored(), 0);
      Assert.assertEquals(reader.getEntriesRead(), 0);
      Assert.assertEquals(reader.getEntriesRejected(), 0);
      Assert.assertEquals(reader.getLastEntryLineNumber(), -1);
    } finally {
      reader.close();
    }
  }
  /**
   * Attempt to read a single entry.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test(dependsOnMethods = { "testReadEntryEmptyStream" })
  public void testReadEntrySingle() throws Exception {
    final String ldifString = "dn: cn=john, dc=foo, dc=com\n"
        + "objectClass: top\n" + "objectClass: person\n" + "cn: john\n"
        + "sn: smith\n";
    LDIFReader reader = createLDIFReader(ldifString);
    try {
      Entry entry = reader.readEntry();
      Assert.assertNotNull(entry);
      Assert.assertEquals(entry.getDN(), DN
          .decode("cn=john, dc=foo, dc=com"));
      Assert.assertTrue(entry.hasObjectClass(OC_TOP));
      Assert.assertTrue(entry.hasObjectClass(OC_PERSON));
      Assert.assertTrue(entry.hasValue(AT_CN, null, new AttributeValue(
          AT_CN, "john")));
      Assert.assertTrue(entry.hasValue(AT_SN, null, new AttributeValue(
          AT_SN, "smith")));
      Assert.assertNull(reader.readEntry());
      Assert.assertEquals(reader.getEntriesIgnored(), 0);
      Assert.assertEquals(reader.getEntriesRead(), 1);
      Assert.assertEquals(reader.getEntriesRejected(), 0);
      Assert.assertEquals(reader.getLastEntryLineNumber(), 1);
    } finally {
      reader.close();
    }
  }
  /**
   * Attempt to read an entry containing a folded line.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test(dependsOnMethods = { "testReadEntrySingle" })
  public void testReadEntryFoldedLine() throws Exception {
    final String ldifString = "dn: cn=john, dc=foo, dc=com\n"
        + "objectClass: top\n" + "objectClass: person\n" + "cn: john\n"
        + "sn: smith\n" + "description: once upon a time\n"
        + "  in the west\n";
    LDIFReader reader = createLDIFReader(ldifString);
    try {
      Entry entry = reader.readEntry();
      Assert.assertNotNull(entry);
      Assert.assertTrue(entry.hasValue(AT_DESCR, null, new AttributeValue(
          AT_DESCR, "once upon a time in the west")));
    } finally {
      reader.close();
    }
  }
  /**
   * Attempt to read an entry containing a base64 line.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test(dependsOnMethods = { "testReadEntrySingle" })
  public void testReadEntryBase64() throws Exception {
    final String ldifString = "dn: cn=john, dc=foo, dc=com\n"
        + "objectClass: top\n" + "objectClass: person\n" + "cn: john\n"
        + "sn: smith\n"
        + "description:: b25jZSB1cG9uIGEgdGltZSBpbiB0aGUgd2VzdA==\n";
    LDIFReader reader = createLDIFReader(ldifString);
    try {
      Entry entry = reader.readEntry();
      Assert.assertNotNull(entry);
      Assert.assertTrue(entry.hasValue(AT_DESCR, null, new AttributeValue(
          AT_DESCR, "once upon a time in the west")));
    } finally {
      reader.close();
    }
  }
  /**
   * Attempt to read multiple entries.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test(dependsOnMethods = { "testReadEntrySingle" })
  public void testReadEntryMultiple() throws Exception {
    final String ldifString = "dn: cn=john, dc=foo, dc=com\n"
        + "objectClass: top\n" + "objectClass: person\n" + "cn: john\n"
        + "sn: smith\n" + "\n" + "dn: cn=anne, dc=foo, dc=com\n"
        + "objectClass: top\n" + "objectClass: person\n" + "cn: anne\n"
        + "sn: other\n" + "\n";
    LDIFReader reader = createLDIFReader(ldifString);
    try {
      reader.readEntry();
      Entry entry = reader.readEntry();
      Assert.assertNotNull(entry);
      Assert.assertEquals(entry.getDN(), DN
          .decode("cn=anne, dc=foo, dc=com"));
      Assert.assertTrue(entry.hasObjectClass(OC_TOP));
      Assert.assertTrue(entry.hasObjectClass(OC_PERSON));
      Assert.assertTrue(entry.hasValue(AT_CN, null, new AttributeValue(
          AT_CN, "anne")));
      Assert.assertTrue(entry.hasValue(AT_SN, null, new AttributeValue(
          AT_SN, "other")));
      Assert.assertNull(reader.readEntry());
      Assert.assertEquals(reader.getEntriesIgnored(), 0);
      Assert.assertEquals(reader.getEntriesRead(), 2);
      Assert.assertEquals(reader.getEntriesRejected(), 0);
      Assert.assertEquals(reader.getLastEntryLineNumber(), 7);
    } finally {
      reader.close();
    }
  }
  /**
   * Attempt to read multiple changes.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test(dependsOnMethods = { "testChangeRecordEmptyStream" })
  public void testReadChangeMultiple() throws Exception {
    LDIFReader reader = createLDIFReader(VALID_LDIF);
    try {
      ChangeRecordEntry change;
      AddChangeRecordEntry add;
      DeleteChangeRecordEntry delete;
      ModifyChangeRecordEntry modify;
      ModifyDNChangeRecordEntry modifyDN;
      DN dn;
      RDN rdn;
      Iterator<LDAPModification> i;
      Modification mod;
      Attribute attr;
      LinkedHashSet<AttributeValue> values;
      // Change record #1.
      change = reader.readChangeRecord(false);
      Assert.assertTrue(change instanceof AddChangeRecordEntry);
      add = (AddChangeRecordEntry) change;
      dn = DN.decode("cn=Fiona Jensen, ou=Marketing, dc=airius, dc=com");
      Assert.assertEquals(add.getDN(), dn);
      List<Attribute> attrs = new ArrayList<Attribute>();
      values = new LinkedHashSet<AttributeValue>();
      values.add(new AttributeValue(AT_OC, "top"));
      values.add(new AttributeValue(AT_OC, "person"));
      values.add(new AttributeValue(AT_OC, "organizationalPerson"));
      attrs.add(new Attribute(AT_OC, "objectclass", values));
      attrs.add(new Attribute("cn", "Fiona Jensen"));
      attrs.add(new Attribute("sn", "Jensen"));
      attrs.add(new Attribute("uid", "fiona"));
      attrs.add(new Attribute("telephonenumber", "+1 408 555 1212"));
      Assert.assertTrue(add.getAttributes().containsAll(attrs));
      // Change record #2.
      change = reader.readChangeRecord(false);
      Assert.assertTrue(change instanceof DeleteChangeRecordEntry);
      delete = (DeleteChangeRecordEntry) change;
      dn = DN.decode("cn=Robert Jensen, ou=Marketing, dc=airius, dc=com");
      Assert.assertEquals(delete.getDN(), dn);
      // Change record #3.
      change = reader.readChangeRecord(false);
      Assert.assertTrue(change instanceof ModifyDNChangeRecordEntry);
      modifyDN = (ModifyDNChangeRecordEntry) change;
      dn = DN
          .decode("cn=Paul Jensen, ou=Product Development, dc=airius, dc=com");
      Assert.assertEquals(modifyDN.getDN(), dn);
      rdn = RDN.decode("cn=paula jensen");
      Assert.assertEquals(modifyDN.getNewRDN(), rdn);
      Assert.assertNull(modifyDN.getNewSuperiorDN());
      Assert.assertTrue(modifyDN.deleteOldRDN());
      // Change record #4.
      change = reader.readChangeRecord(false);
      Assert.assertTrue(change instanceof ModifyDNChangeRecordEntry);
      modifyDN = (ModifyDNChangeRecordEntry) change;
      dn = DN
          .decode("ou=PD Accountants, ou=Product Development, dc=airius, dc=com");
      Assert.assertEquals(modifyDN.getDN(), dn);
      rdn = RDN.decode("ou=Product Development Accountants");
      Assert.assertEquals(modifyDN.getNewRDN(), rdn);
      dn = DN.decode("ou=Accounting, dc=airius, dc=com");
      Assert.assertEquals(modifyDN.getNewSuperiorDN(), dn);
      Assert.assertFalse(modifyDN.deleteOldRDN());
      // Change record #5.
      change = reader.readChangeRecord(false);
      Assert.assertTrue(change instanceof ModifyChangeRecordEntry);
      modify = (ModifyChangeRecordEntry) change;
      dn = DN
          .decode("cn=Paula Jensen, ou=Product Development, dc=airius, dc=com");
      Assert.assertEquals(modify.getDN(), dn);
      i = modify.getModifications().iterator();
      Assert.assertTrue(i.hasNext());
      mod = i.next().toModification();
      Assert.assertEquals(mod.getModificationType(), ModificationType.ADD);
      attr = new Attribute("postaladdress",
          "123 Anystreet $ Sunnyvale, CA $ 94086");
      Assert.assertEquals(mod.getAttribute(), attr);
      Assert.assertTrue(i.hasNext());
      mod = i.next().toModification();
      Assert.assertEquals(mod.getModificationType(),
          ModificationType.DELETE);
      attr = new Attribute(AT_DESCR);
      Assert.assertEquals(mod.getAttribute(), attr);
      Assert.assertTrue(i.hasNext());
      mod = i.next().toModification();
      Assert.assertEquals(mod.getModificationType(),
          ModificationType.REPLACE);
      values = new LinkedHashSet<AttributeValue>();
      values.add(new AttributeValue(AT_TELN, "+1 408 555 1234"));
      values.add(new AttributeValue(AT_TELN, "+1 408 555 5678"));
      attr = new Attribute(AT_TELN, "telephonenumber", values);
      Assert.assertEquals(mod.getAttribute(), attr);
      Assert.assertTrue(i.hasNext());
      mod = i.next().toModification();
      Assert.assertEquals(mod.getModificationType(),
          ModificationType.DELETE);
      attr = new Attribute("facsimiletelephonenumber", "+1 408 555 9876");
      Assert.assertEquals(mod.getAttribute(), attr);
      Assert.assertFalse(i.hasNext());
      // Change record #6.
      change = reader.readChangeRecord(false);
      Assert.assertTrue(change instanceof ModifyChangeRecordEntry);
      modify = (ModifyChangeRecordEntry) change;
      dn = DN
          .decode("cn=Ingrid Jensen, ou=Product Support, dc=airius, dc=com");
      Assert.assertEquals(modify.getDN(), dn);
      i = modify.getModifications().iterator();
      Assert.assertTrue(i.hasNext());
      mod = i.next().toModification();
      Assert.assertEquals(mod.getModificationType(),
          ModificationType.REPLACE);
      attr = new Attribute(DirectoryServer
          .getAttributeType("postaladdress"));
      Assert.assertEquals(mod.getAttribute(), attr);
      // Change record #7.
      change = reader.readChangeRecord(false);
      Assert.assertTrue(change instanceof ModifyChangeRecordEntry);
      modify = (ModifyChangeRecordEntry) change;
      Assert.assertTrue(modify.getDN().isNullDN());
      i = modify.getModifications().iterator();
      Assert.assertTrue(i.hasNext());
      mod = i.next().toModification();
      Assert.assertEquals(mod.getModificationType(),
          ModificationType.DELETE);
      attr = new Attribute(AT_DESCR);
      Assert.assertEquals(mod.getAttribute(), attr);
      // Change record #8.
      change = reader.readChangeRecord(false);
      Assert.assertTrue(change instanceof ModifyChangeRecordEntry);
      modify = (ModifyChangeRecordEntry) change;
      dn = DN.decode("uid=rogasawara, ou=\u55b6\u696d\u90e8, o=airius");
      Assert.assertEquals(modify.getDN(), dn);
      i = modify.getModifications().iterator();
      Assert.assertTrue(i.hasNext());
      mod = i.next().toModification();
      Assert.assertEquals(mod.getModificationType(),
          ModificationType.DELETE);
      attr = new Attribute(AT_DESCR);
      Assert.assertEquals(mod.getAttribute(), attr);
      Assert.assertFalse(i.hasNext());
      // Check final state.
      Assert.assertNull(reader.readChangeRecord(false));
      Assert.assertEquals(reader.getEntriesIgnored(), 0);
      Assert.assertEquals(reader.getEntriesRead(), 0);
      Assert.assertEquals(reader.getEntriesRejected(), 0);
      Assert.assertEquals(reader.getLastEntryLineNumber(), 72);
    } finally {
      reader.close();
    }
  }
  /**
   * Attempt to read multiple changes and rejects one.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test(dependsOnMethods = { "testReadChangeMultiple" })
  public void testReadChangeMultipleAndReject() throws Exception {
    LDIFReader reader = createLDIFReader(VALID_LDIF);
    try {
      reader.readChangeRecord(false);
      reader.readChangeRecord(false);
      reader.readChangeRecord(false);
      reader.readChangeRecord(false);
      reader.rejectLastEntry("Rejected");
      reader.readChangeRecord(false);
      reader.rejectLastEntry("Rejected");
      reader.readChangeRecord(false);
      reader.readChangeRecord(false);
      reader.readChangeRecord(false);
      // Check final state.
      Assert.assertNull(reader.readChangeRecord(false));
      Assert.assertEquals(reader.getEntriesRejected(), 2);
    } finally {
      reader.close();
    }
  }
  /**
   * Attempt to read a change containing a file-based attribute.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test(dependsOnMethods = { "testReadChangeMultiple" })
  public void testReadChangeWithFileBaseAttribute() throws Exception {
    StringBuilder buffer = new StringBuilder(TEMP_FILE_LDIF);
    buffer.append(TEMP_FILE.getCanonicalPath());
    buffer.append("\n");
    LDIFReader reader = createLDIFReader(buffer.toString());
    try {
      ChangeRecordEntry change = reader.readChangeRecord(false);
      Assert.assertTrue(change instanceof AddChangeRecordEntry);
      AddChangeRecordEntry add = (AddChangeRecordEntry) change;
      DN dn = DN.decode("cn=john smith, dc=com");
      Assert.assertEquals(add.getDN(), dn);
      Attribute attr = new Attribute("description", TEMP_FILE_STRING);
      Assert.assertTrue(add.getAttributes().contains(attr));
      // Check final state.
      Assert.assertNull(reader.readChangeRecord(false));
    } finally {
      reader.close();
    }
  }
  /**
   * LDIF change reader - invalid data provider.
   *
   * @return Returns an array of invalid LDIF change records.
   */
  @DataProvider(name = "invalidLDIFChangeRecords")
  public Object[][] createInvalidLDIFChangeRecords() {
    return new Object[][] {
        {
          "changetype: add\n" +
          "objectClass: top\n" +
          "objectClass: person\n" +
          "cn: john\n" +
          "sn: smith\n"
        },
        {
          "dn: cn=john smith, dc=com\n" +
          "dn: cn=john smith, dc=com\n" +
          "changetype: add\n" +
          "objectClass: top\n" +
          "objectClass: person\n" +
          "cn: john\n" +
          "sn: smith\n"
        },
        {
          ": cn=john smith, dc=com\n" +
          "changetype: add\n" +
          "objectClass: top\n" +
          "objectClass: person\n" +
          "cn: john\n" +
          "sn: smith\n"
        },
        {
          "x: cn=john smith, dc=com\n" +
          "changetype: add\n" +
          "objectClass: top\n" +
          "objectClass: person\n" +
          "cn: john\n" +
          "sn: smith\n"
        },
        {
          "dn: foo\n" +
          "changetype: add\n" +
          "objectClass: top\n" +
          "objectClass: person\n" +
          "cn: john\n" +
          "sn: smith\n"
        },
        {
          "dn: cn,=john smith, dc=com\n" +
          "changetype: add\n" +
          "objectClass: top\n" +
          "objectClass: person\n" +
          "cn: john\n" +
          "sn: smith\n"
        },
        {
          "dn: cn=john smith, dc=com\n" +
          "chaxxngetype: add\n" +
          "objectClass: top\n" +
          "objectClass: person\n" +
          "cn: john\n" +
          "sn: smith\n"
        },
        {
          "dn: cn=john smith, dc=com\n" +
          "changetype: foo\n" +
          "objectClass: top\n" +
          "objectClass: person\n" +
          "cn: john\n" +
          "sn: smith\n"
        },
        {
          "dn: cn=john smith, dc=com\n" +
          "changetype:: add\n" +
          "objectClass: top\n" +
          "objectClass: person\n" +
          "cn: john\n" +
          "sn: smith\n"
        },
        {
          "dn: cn=john smith, dc=com\n" +
          ": add\n" +
          "objectClass: top\n" +
          "objectClass: person\n" +
          "cn: john\n" +
          "sn: smith\n"
        },
        {
          "dn: cn=john smith, dc=com\n" +
          "changetype:\n" +
          "objectClass: top\n" +
          "objectClass: person\n" +
          "cn: john\n" +
          "sn: smith\n"
        },
        {
          "dn: cn=john smith, dc=com\n" +
          "\n" +
          "objectClass: top\n" +
          "objectClass: person\n" +
          "cn: john\n" +
          "sn: smith\n"
        },
        {
          "dn: cn=john smith, dc=com\n" +
          "changetype: add\n" +
          "xxxx\n" +
          "objectClass: person\n" +
          "cn: john\n" +
          "sn: smith\n"
        },
        {
          "dn: cn=john smith, dc=com\n" +
          "changetype: add\n" +
          "objectClass: top\n" +
          "objectClass: person\n" +
          "cn: john\n" +
          "cn: john\n" +
          "sn: smith\n"
        },
        {
          "dn: cn=john smith, dc=com\n" +
          "changetype: add\n" +
          "objectClass: top\n" +
          "objectClass: person\n" +
          "cn: john\n" +
          "sn: smith\n" +
          "cn: john\n"
        },
        {
          "dn: cn=john smith, dc=com\n" +
          "changetype: add\n" +
          ": top\n" +
          "objectClass: person\n" +
          "cn: john\n" +
          "objectClass: person\n" +
          "sn: smith\n"
        },
        {
          "dn: cn=john smith, dc=com\n" +
          "changetype: add\n" +
          "objectclass: top\n" +
          "objectClass: person\n" +
          "cn: john\n" +
          "sn: smith\n" +
          "description:: YnJva2VuIGJhc2U2NA*=="
        },
        {
          "dn:: YnJva2VuIGJhc2U2NA*==" +
          "changetype: add\n" +
          "objectclass: top\n" +
          "objectClass: person\n" +
          "cn: john\n" +
          "sn: smith\n"
        },
        {
          "dn:: Y249YnJva2VuIGJhc2U2NCBkbix4" +
          "changetype: add\n" +
          "objectclass: top\n" +
          "objectClass: person\n" +
          "cn: john\n" +
          "sn: smith\n"
        },
        {
          "dn: cn=john smith, dc=com\n" +
          "changetype: add\n" +
          "objectclass: top\n" +
          "objectClass: person\n" +
          "cn: john\n" +
          "sn: smith\n" +
          "description:< brok@n:///bad/url"
        },
        {
          "dn: cn=john smith, dc=com\n" +
          "changetype: add\n" +
          "objectclass: top\n" +
          "objectClass: person\n" +
          "cn: john\n" +
          "sn: smith\n" +
          "description:< file:///bad/path/name"
        },
        {
          "dn: cn=john smith, dc=com\n" +
          "changetype: delete\n" +
          "objectclass: top\n" +
          "objectClass: person\n" +
          "cn: john\n" +
          "sn: smith\n" +
          "description:< file:///bad/path/name"
        },
        {
          "dn: cn=john smith, dc=com\n" +
          "changetype: modrdn\n"
        },
        {
          "dn: cn=john smith, dc=com\n" +
          "changetype: modrdn\n" +
          "newrdn: x\n"
        },
        {
          "dn: cn=john smith, dc=com\n" +
          "changetype: modrdn\n" +
          "newrdn: cn=foo\n"
        },
        {
          "dn: cn=john smith, dc=com\n" +
          "changetype: modrdn\n" +
          "newrdn: cn=foo\n" +
          "deleteoldxx: xxx\n"
        },
        {
          "dn: cn=john smith, dc=com\n" +
          "changetype: modrdn\n" +
          "newrdn: cn=foo\n" +
          "deleteoldrdn: xxx\n"
        },
        {
          "dn: cn=john smith, dc=com\n" +
          "changetype: modrdn\n" +
          "newrdn: cn=foo\n" +
          "deleteoldrdn: 0\n" +
          "newsu: xxxx\n"
        },
        {
          "dn: cn=john smith, dc=com\n" +
          "changetype: modrdn\n" +
          "newrdn: cn=foo\n" +
          "deleteoldrdn: 0\n" +
          "newsuperior: xxxx\n"
        },
    };
  }
  /**
   * Tests the read change record method against invalid LDIF records.
   *
   * @param ldifString
   *          The invalid LDIF change record.
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test(dataProvider = "invalidLDIFChangeRecords",
      expectedExceptions = { LDIFException.class })
  public void testReadChangeInvalidData(String ldifString) throws Exception {
    LDIFReader reader = createLDIFReader(ldifString);
    ChangeRecordEntry change = null;
    try {
      change = reader.readChangeRecord(false);
    } finally {
      reader.close();
    }
    Assert.fail("Expected exception but got result: "
        + change.getChangeOperationType() + " - " + change.getDN());
  }
  /**
   * Create an LDIF reader from a string of LDIF.
   *
   * @param ldifString
   *          The string of LDIF. *
   * @return Returns the LDIF reader.
   * @throws Exception
   *           If an error occurred.
   */
  private LDIFReader createLDIFReader(String ldifString) throws Exception {
    byte[] bytes = StaticUtils.getBytes(ldifString);
    LDIFReader reader = new LDIFReader(new LDIFImportConfig(
        new ByteArrayInputStream(bytes)));
    return reader;
  }
}
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/util/TestModifyChangeRecordEntry.java
@@ -26,12 +26,16 @@
 */
package org.opends.server.util;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.opends.server.TestCaseUtils;
import org.opends.server.protocols.ldap.LDAPAttribute;
import org.opends.server.protocols.ldap.LDAPModification;
import org.opends.server.types.Attribute;
import org.opends.server.types.DN;
import org.opends.server.types.LDIFImportConfig;
import org.opends.server.types.ModificationType;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
@@ -45,8 +49,11 @@
 * been overridden.
 */
public final class TestModifyChangeRecordEntry extends UtilTestCase {
  // An empty LDIF reader.
  private LDIFReader emptyReader;
  // Set of changes.
  private List<LDAPModification> modifications;
  // The attribute being added in the modifications.
  private Attribute attribute;
  /**
   * Once-only initialization.
@@ -60,9 +67,13 @@
    // start the server.
    TestCaseUtils.startServer();
    InputStream stream = new ByteArrayInputStream(new byte[0]);
    LDIFImportConfig config = new LDIFImportConfig(stream);
    emptyReader = new LDIFReader(config);
    // Create a simple set of modifications.
    modifications = new ArrayList<LDAPModification>();
    attribute = new Attribute("cn", "hello world");
    LDAPAttribute lattribute = new LDAPAttribute(attribute);
    LDAPModification modification = new LDAPModification(
        ModificationType.ADD, lattribute);
    modifications.add(modification);
  }
  /**
@@ -74,7 +85,7 @@
  @Test
  public void testConstructorNullDN() throws Exception {
    ModifyChangeRecordEntry entry = new ModifyChangeRecordEntry(null,
        emptyReader);
        modifications);
    Assert.assertEquals(entry.getDN(), new DN());
  }
@@ -88,7 +99,7 @@
  @Test
  public void testConstructorEmptyDN() throws Exception {
    ModifyChangeRecordEntry entry = new ModifyChangeRecordEntry(new DN(),
        emptyReader);
        modifications);
    Assert.assertEquals(entry.getDN(), new DN());
  }
@@ -105,7 +116,7 @@
    DN testDN2 = DN.decode("dc=hello, dc=world");
    ModifyChangeRecordEntry entry = new ModifyChangeRecordEntry(testDN1,
        emptyReader);
        modifications);
    Assert.assertEquals(entry.getDN(), testDN2);
  }
@@ -119,28 +130,43 @@
  @Test
  public void testChangeOperationType() throws Exception {
    ModifyChangeRecordEntry entry = new ModifyChangeRecordEntry(null,
        emptyReader);
        modifications);
    Assert.assertEquals(entry.getChangeOperationType(),
        ChangeOperationType.MODIFY);
  }
  /**
   * Tests parse and getAttributes methods.
   * <p>
   * Due to tight coupling between the
   * {@link ModifyChangeRecordEntry#parse(java.util.LinkedList, long)}
   * method and the {@link LDIFReader} class it is not easy to test the
   * {@link ModifyChangeRecordEntry#getModifications()} method. Instead,
   * we'll test that in the {@link LDIFReader} test suite.
   * Tests getModifications method for empty modifications.
   * 
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test(enabled = false)
  public void testGetModifications() throws Exception {
    // FIXME: fix tight-coupling between parse() and LDIFReader.
    Assert.assertTrue(false);
  @Test
  public void testGetModificationsEmpty() throws Exception {
    List<LDAPModification> empty = Collections.emptyList();
    ModifyChangeRecordEntry entry = new ModifyChangeRecordEntry(null, empty);
    List<LDAPModification> mods = entry.getModifications();
    Assert.assertEquals(mods.size(), 0);
  }
  /**
   * Tests getModifications method for non-empty modifications.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testGetModificationsNonEmpty() throws Exception {
    ModifyChangeRecordEntry entry = new ModifyChangeRecordEntry(null,
        modifications);
    List<LDAPModification> mods = entry.getModifications();
    Assert.assertEquals(mods.size(), 1);
    LDAPModification first = mods.get(0);
    Assert.assertEquals(first.getModificationType(), ModificationType.ADD);
    Assert.assertEquals(first.getAttribute().toAttribute(), attribute);
  }
}
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/util/TestModifyDNChangeRecordEntry.java
@@ -26,12 +26,9 @@
 */
package org.opends.server.util;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import org.opends.server.TestCaseUtils;
import org.opends.server.types.DN;
import org.opends.server.types.LDIFImportConfig;
import org.opends.server.types.RDN;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
@@ -45,8 +42,9 @@
 * been overridden.
 */
public final class TestModifyDNChangeRecordEntry extends UtilTestCase {
  // An empty LDIF reader.
  private LDIFReader emptyReader;
  private DN newSuperiorDN;
  private RDN newRDN;
  /**
   * Once-only initialization.
@@ -60,9 +58,8 @@
    // start the server.
    TestCaseUtils.startServer();
    InputStream stream = new ByteArrayInputStream(new byte[0]);
    LDIFImportConfig config = new LDIFImportConfig(stream);
    emptyReader = new LDIFReader(config);
    newSuperiorDN = DN.decode("dc=com");
    newRDN = RDN.decode("dc=foo");
  }
  /**
@@ -74,7 +71,7 @@
  @Test
  public void testConstructorNullDN() throws Exception {
    ModifyDNChangeRecordEntry entry = new ModifyDNChangeRecordEntry(null,
        emptyReader);
        newSuperiorDN, newRDN, false);
    Assert.assertEquals(entry.getDN(), new DN());
  }
@@ -88,7 +85,7 @@
  @Test
  public void testConstructorEmptyDN() throws Exception {
    ModifyDNChangeRecordEntry entry = new ModifyDNChangeRecordEntry(
        new DN(), emptyReader);
        new DN(), newSuperiorDN, newRDN, false);
    Assert.assertEquals(entry.getDN(), new DN());
  }
@@ -105,7 +102,7 @@
    DN testDN2 = DN.decode("dc=hello, dc=world");
    ModifyDNChangeRecordEntry entry = new ModifyDNChangeRecordEntry(
        testDN1, emptyReader);
        testDN1, newSuperiorDN, newRDN, false);
    Assert.assertEquals(entry.getDN(), testDN2);
  }
@@ -119,63 +116,66 @@
  @Test
  public void testChangeOperationType() throws Exception {
    ModifyDNChangeRecordEntry entry = new ModifyDNChangeRecordEntry(null,
        emptyReader);
        newSuperiorDN, newRDN, false);
    Assert.assertEquals(entry.getChangeOperationType(),
        ChangeOperationType.MODIFY_DN);
  }
  /**
   * Tests parse and getNewRDN methods.
   * <p>
   * Due to tight coupling between the
   * {@link ModifyDNChangeRecordEntry#parse(java.util.LinkedList, long)}
   * method and the {@link LDIFReader} class it is not easy to test the
   * {@link ModifyDNChangeRecordEntry#getNewRDN()} method. Instead,
   * we'll test that in the {@link LDIFReader} test suite.
   * Tests getNewRDN method.
   * 
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test(enabled = false)
  @Test
  public void testGetNewRDN() throws Exception {
    // FIXME: fix tight-coupling between parse() and LDIFReader.
    Assert.assertTrue(false);
    ModifyDNChangeRecordEntry entry = new ModifyDNChangeRecordEntry(null,
        newSuperiorDN, newRDN, false);
    Assert.assertEquals(entry.getNewRDN(), newRDN.duplicate());
  }
  /**
   * Tests parse and getNewSuperiorDN methods.
   * <p>
   * Due to tight coupling between the
   * {@link ModifyDNChangeRecordEntry#parse(java.util.LinkedList, long)}
   * method and the {@link LDIFReader} class it is not easy to test the
   * {@link ModifyDNChangeRecordEntry#getNewSuperiorDN()} method.
   * Instead, we'll test that in the {@link LDIFReader} test suite.
   * Tests getNewSuperiorDN method.
   * 
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test(enabled = false)
  @Test
  public void testGetNewSuperiorDN() throws Exception {
    // FIXME: fix tight-coupling between parse() and LDIFReader.
    Assert.assertTrue(false);
    ModifyDNChangeRecordEntry entry = new ModifyDNChangeRecordEntry(null,
        newSuperiorDN, newRDN, false);
    Assert
        .assertEquals(entry.getNewSuperiorDN(), newSuperiorDN.duplicate());
  }
  /**
   * Tests parse and deleteOldRDN methods.
   * <p>
   * Due to tight coupling between the
   * {@link ModifyDNChangeRecordEntry#parse(java.util.LinkedList, long)}
   * method and the {@link LDIFReader} class it is not easy to test the
   * {@link ModifyDNChangeRecordEntry#deleteOldRDN()} method. Instead,
   * we'll test that in the {@link LDIFReader} test suite.
   * Tests deleteOldRDN method when false.
   * 
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test(enabled = false)
  public void testDeleteOldRDN() throws Exception {
    // FIXME: fix tight-coupling between parse() and LDIFReader.
    Assert.assertTrue(false);
  @Test
  public void testDeleteOldRDNFalse() throws Exception {
    ModifyDNChangeRecordEntry entry = new ModifyDNChangeRecordEntry(null,
        newSuperiorDN, newRDN, false);
    Assert.assertEquals(entry.deleteOldRDN(), false);
  }
  /**
   * Tests deleteOldRDN method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testDeleteOldRDNTrue() throws Exception {
    ModifyDNChangeRecordEntry entry = new ModifyDNChangeRecordEntry(null,
        newSuperiorDN, newRDN, true);
    Assert.assertEquals(entry.deleteOldRDN(), true);
  }
}