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

pgamba
12.09.2007 f912fe883b2fd613b4115e29a2cf0c237a135b0c
opends/src/messages/messages/replication.properties
@@ -229,4 +229,8 @@
 testing existence or creating the replication backend : %s
 SEVERE_ERR_DELETE_REPL_BACKEND_FAILED_90=An unexpected error occured when \
 deleting the replication backend : %s
 SEVERE_ERR_EXPORT_CANNOT_WRITE_ENTRY_TO_LDIF_91=An error occured when \
 exporting to LDIF the entry %s : %s
SEVERE_ERR_BACKEND_CANNOT_CREATE_LDIF_WRITER_92 =An error occured when \
 creating the LDIF writer to export backend : %s
 
opends/src/server/org/opends/server/replication/protocol/AddMsg.java
@@ -288,4 +288,13 @@
  {
    parentUniqueId = uid;
  }
  /**
   * Get the parent unique id of this add msg.
   * @return the parent unique id.
   */
  public String getParentUid()
  {
    return parentUniqueId;
  }
}
opends/src/server/org/opends/server/replication/protocol/ModifyDNMsg.java
@@ -235,7 +235,7 @@
  @Override
  public String toString()
  {
    return ("Modify DN " + getDn() + " " + newRDN + " " + newSuperior + " " +
    return ("MODDN " + getDn() + " " + newRDN + " " + newSuperior + " " +
            getChangeNumber());
  }
opends/src/server/org/opends/server/replication/protocol/ModifyMsg.java
@@ -232,6 +232,6 @@
  @Override
  public String toString()
  {
    return("Modify " + getDn() + " " + getChangeNumber());
    return("MOD " + getDn() + " " + getChangeNumber());
  }
}
opends/src/server/org/opends/server/replication/server/ReplicationBackend.java
@@ -26,12 +26,23 @@
 */
package org.opends.server.replication.server;
import static org.opends.messages.BackendMessages.*;
import static org.opends.messages.JebMessages.INFO_JEB_EXPORT_FINAL_STATUS;
import static org.opends.messages.JebMessages.INFO_JEB_EXPORT_PROGRESS_REPORT;
import static org.opends.messages.ReplicationMessages.*;
import static org.opends.server.loggers.ErrorLogger.logError;
import static org.opends.server.loggers.debug.DebugLogger.debugEnabled;
import static org.opends.server.loggers.debug.DebugLogger.getTracer;
import static org.opends.server.util.StaticUtils.getExceptionMessage;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import org.opends.messages.Message;
import org.opends.server.admin.Configuration;
@@ -47,6 +58,15 @@
import org.opends.server.core.ModifyOperation;
import org.opends.server.core.SearchOperation;
import org.opends.server.loggers.debug.DebugTracer;
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.replication.protocol.AddMsg;
import org.opends.server.replication.protocol.DeleteMsg;
import org.opends.server.replication.protocol.ModifyDNMsg;
import org.opends.server.replication.protocol.ModifyMsg;
import org.opends.server.replication.protocol.UpdateMessage;
import org.opends.server.types.Attribute;
import org.opends.server.types.AttributeType;
import org.opends.server.types.AttributeValue;
import org.opends.server.types.BackupConfig;
import org.opends.server.types.BackupDirectory;
import org.opends.server.types.ConditionResult;
@@ -58,8 +78,14 @@
import org.opends.server.types.LDIFExportConfig;
import org.opends.server.types.LDIFImportConfig;
import org.opends.server.types.LDIFImportResult;
import org.opends.server.types.RawAttribute;
import org.opends.server.types.RestoreConfig;
import org.opends.server.types.ResultCode;
import org.opends.server.util.AddChangeRecordEntry;
import org.opends.server.util.DeleteChangeRecordEntry;
import org.opends.server.util.LDIFWriter;
import org.opends.server.util.ModifyChangeRecordEntry;
import org.opends.server.util.ModifyDNChangeRecordEntry;
import org.opends.server.util.Validator;
/**
@@ -83,6 +109,8 @@
   */
  private static final DebugTracer TRACER = getTracer();
  private static final String EXPORT_BASE_DN = "dc=replicationChanges";
  // The base DNs for this backend.
  private DN[] baseDNs;
@@ -109,6 +137,21 @@
  private JEBackendCfg cfg;
  /**
   * The number of milliseconds between job progress reports.
   */
  private long progressInterval = 10000;
  /**
   * The current number of entries exported.
   */
  private long exportedCount = 0;
  /**
   * The current number of entries skipped.
   */
  private long skippedCount = 0;
  /**
   * Creates a new backend with the provided information.  All backend
   * implementations must implement a default constructor that use
   * <CODE>super()</CODE> to invoke this constructor.
@@ -345,16 +388,323 @@
   */
  public boolean supportsLDIFExport()
  {
    return false;
    return true;
  }
  /**
   * {@inheritDoc}
   */
  public synchronized void exportLDIF(LDIFExportConfig exportConfig)
         throws DirectoryException
  throws DirectoryException
  {
    // TODO
    List<DN> includeBranches = exportConfig.getIncludeBranches();
    DN baseDN;
    ArrayList<ReplicationCache> exportContainers =
      new ArrayList<ReplicationCache>();
    Iterator<ReplicationCache> rcachei = server.getCacheIterator();
    if (rcachei != null)
    {
      while (rcachei.hasNext())
      {
        ReplicationCache rc = rcachei.next();
        // Skip containers that are not covered by the include branches.
        baseDN = DN.decode(rc.getBaseDn().toString() + "," + EXPORT_BASE_DN);
        if (includeBranches == null || includeBranches.isEmpty())
        {
          exportContainers.add(rc);
        }
        else
        {
          for (DN includeBranch : includeBranches)
          {
            if (includeBranch.isDescendantOf(baseDN) ||
                includeBranch.isAncestorOf(baseDN))
            {
              exportContainers.add(rc);
            }
          }
        }
      }
    }
    // Make a note of the time we started.
    long startTime = System.currentTimeMillis();
    // Start a timer for the progress report.
    Timer timer = new Timer();
    TimerTask progressTask = new ProgressTask();
    timer.scheduleAtFixedRate(progressTask, progressInterval,
        progressInterval);
    // Create the LDIF writer.
    LDIFWriter ldifWriter;
    try
    {
      ldifWriter = new LDIFWriter(exportConfig);
    }
    catch (Exception e)
    {
      if (debugEnabled())
      {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }
      Message message =
        ERR_BACKEND_CANNOT_CREATE_LDIF_WRITER.get(String.valueOf(e));
      throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
          message, e);
    }
    exportRootChanges(exportContainers, exportConfig, ldifWriter);
    // Iterate through the containers.
    try
    {
      for (ReplicationCache exportContainer : exportContainers)
      {
        exportContainer(exportContainer, exportConfig, ldifWriter);
      }
    }
    finally
    {
      timer.cancel();
      // Close the LDIF writer
      try
      {
        ldifWriter.close();
      }
      catch (Exception e)
      {
        if (debugEnabled())
        {
          TRACER.debugCaught(DebugLogLevel.ERROR, e);
        }
      }
    }
    long finishTime = System.currentTimeMillis();
    long totalTime = (finishTime - startTime);
    float rate = 0;
    if (totalTime > 0)
    {
      rate = 1000f*exportedCount / totalTime;
    }
    Message message = INFO_JEB_EXPORT_FINAL_STATUS.get(
        exportedCount, skippedCount, totalTime/1000, rate);
    logError(message);
  }
  /*
   * Exports the root changes of the export, and one entry by domain.
   */
  private void exportRootChanges(List<ReplicationCache> exportContainers,
      LDIFExportConfig exportConfig, LDIFWriter ldifWriter)
  {
    Map<AttributeType,List<Attribute>> attributes =
      new HashMap<AttributeType,List<Attribute>>();
    ArrayList<Attribute> ldapAttrList = new ArrayList<Attribute>();
    AttributeType ocType=
      DirectoryServer.getAttributeType("objectclass", true);
    LinkedHashSet<AttributeValue> ocValues =
      new LinkedHashSet<AttributeValue>();
    ocValues.add(new AttributeValue(ocType, "top"));
    ocValues.add(new AttributeValue(ocType, "domain"));
    Attribute ocAttr = new Attribute(ocType, "objectclass", ocValues);
    ldapAttrList.add(ocAttr);
    attributes.put(ocType, ldapAttrList);
    try
    {
      AddChangeRecordEntry changeRecord =
        new AddChangeRecordEntry(DN.decode(EXPORT_BASE_DN),
                               attributes);
      ldifWriter.writeChangeRecord(changeRecord);
    }
    catch (Exception e) {}
    for (ReplicationCache exportContainer : exportContainers)
    {
      attributes.clear();
      ldapAttrList.clear();
      ldapAttrList.add(ocAttr);
      AttributeType stateType=
        DirectoryServer.getAttributeType("state", true);
      LinkedHashSet<AttributeValue> stateValues =
        new LinkedHashSet<AttributeValue>();
      stateValues.add(new AttributeValue(stateType,
          exportContainer.getDbServerState().toString()));
      TRACER.debugInfo("State=" +
          exportContainer.getDbServerState().toString());
      Attribute stateAttr = new Attribute(ocType, "state", stateValues);
      ldapAttrList.add(stateAttr);
      AttributeType genidType=
        DirectoryServer.getAttributeType("generation-id", true);
      LinkedHashSet<AttributeValue> genidValues =
        new LinkedHashSet<AttributeValue>();
      genidValues.add(new AttributeValue(genidType,
          String.valueOf(exportContainer.getGenerationId())+
          exportContainer.getBaseDn()));
      Attribute genidAttr = new Attribute(ocType, "generation-id", genidValues);
      ldapAttrList.add(genidAttr);
      attributes.put(genidType, ldapAttrList);
      try
      {
        AddChangeRecordEntry changeRecord =
          new AddChangeRecordEntry(DN.decode(
              exportContainer.getBaseDn() + "," + EXPORT_BASE_DN),
              attributes);
        ldifWriter.writeChangeRecord(changeRecord);
      }
      catch (Exception e)
      {
        if (debugEnabled())
        {
          TRACER.debugCaught(DebugLogLevel.ERROR, e);
        }
        Message message = ERR_EXPORT_CANNOT_WRITE_ENTRY_TO_LDIF.get(
            exportContainer.getBaseDn() + "," + EXPORT_BASE_DN,
            String.valueOf(e));
        logError(message);
      }
    }
  }
  /**
   * Export the changes for a given ReplicationCache.
   */
  private void exportContainer(ReplicationCache rc,
      LDIFExportConfig exportConfig, LDIFWriter ldifWriter)
  {
    StringBuilder buffer = new StringBuilder();
    // Walk through the servers
    for (Short serverId : rc.getServers())
    {
      ReplicationIterator ri = rc.getChangelogIterator(serverId,
          null);
      if (ri == null)
        break;
      // Walk through the changes
      while (ri.getChange() != null)
      {
        UpdateMessage msg = ri.getChange();
        exportChange(buffer, msg, exportConfig, ldifWriter);
        if (!ri.next())
          break;
      }
    }
  }
  /**
   * Export one change.
   */
  private void exportChange(StringBuilder buffer, UpdateMessage msg,
      LDIFExportConfig exportConfig, LDIFWriter ldifWriter)
  {
    InternalClientConnection conn =
      InternalClientConnection.getRootConnection();
    String dn = null;
    try
    {
      if (msg instanceof AddMsg)
      {
        AddMsg addMsg = (AddMsg)msg;
        AddOperation op = (AddOperation)msg.createOperation(conn);
        dn = "puid=" + addMsg.getParentUid() + "," +
             "changeNumber=" + msg.getChangeNumber().toString() + "," +
             msg.getDn() +","+ "dc=replicationChanges";
        Map<AttributeType,List<Attribute>> attributes =
          new HashMap<AttributeType,List<Attribute>>();
        for (RawAttribute a : op.getRawAttributes())
        {
          Attribute attr = a.toAttribute();
          AttributeType attrType = attr.getAttributeType();
          List<Attribute> attrs = attributes.get(attrType);
          if (attrs == null)
          {
            attrs = new ArrayList<Attribute>(1);
            attrs.add(attr);
            attributes.put(attrType, attrs);
          }
          else
          {
            attrs.add(attr);
          }
        }
        AddChangeRecordEntry changeRecord =
          new AddChangeRecordEntry(DN.decode(dn), attributes);
        ldifWriter.writeChangeRecord(changeRecord);
      }
      else if (msg instanceof DeleteMsg)
      {
        DeleteMsg delMsg = (DeleteMsg)msg;
        // DN
        dn = "uuid=" + msg.getUniqueId() + "," +
        "changeNumber=" + delMsg.getChangeNumber().toString()+ "," +
        msg.getDn() +","+
        "dc=replicationChanges";
        DeleteChangeRecordEntry changeRecord =
          new DeleteChangeRecordEntry(DN.decode(dn));
        ldifWriter.writeChangeRecord(changeRecord);
      }
      else if (msg instanceof ModifyMsg)
      {
        ModifyOperation op = (ModifyOperation)msg.createOperation(conn);
        // DN
        dn = "uuid=" + msg.getUniqueId() + "," +
        "changeNumber=" + msg.getChangeNumber().toString()+ "," +
        msg.getDn() +","+
        "dc=replicationChanges";
        op.setInternalOperation(true);
        ModifyChangeRecordEntry changeRecord =
          new ModifyChangeRecordEntry(DN.decode(dn),
              op.getRawModifications());
        ldifWriter.writeChangeRecord(changeRecord);
      }
      else if (msg instanceof ModifyDNMsg)
      {
        ModifyDNOperation op = (ModifyDNOperation)msg.createOperation(conn);
        // DN
        dn = "uuid=" + msg.getUniqueId() + "," +
        "changeNumber=" + msg.getChangeNumber().toString()+ "," +
        msg.getDn() +","+
        "dc=replicationChanges";
        op.setInternalOperation(true);
        ModifyDNChangeRecordEntry changeRecord =
          new ModifyDNChangeRecordEntry(DN.decode(dn),
              op.getNewRDN(), op.deleteOldRDN(),
              op.getNewSuperior());
        ldifWriter.writeChangeRecord(changeRecord);
      }
      this.exportedCount++;
    }
    catch (Exception e)
    {
      this.skippedCount++;
      if (debugEnabled())
      {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }
      Message message = ERR_EXPORT_CANNOT_WRITE_ENTRY_TO_LDIF.get(
          dn, String.valueOf(e));
      logError(message);
    }
  }
  /**
@@ -490,4 +840,54 @@
  {
    this.server = server;
  }
  /**
   * This class reports progress of the export job at fixed intervals.
   */
  class ProgressTask extends TimerTask
  {
    /**
     * The number of entries that had been exported at the time of the
     * previous progress report.
     */
    private long previousCount = 0;
    /**
     * The time in milliseconds of the previous progress report.
     */
    private long previousTime;
    /**
     * Create a new export progress task.
     */
    public ProgressTask()
    {
      previousTime = System.currentTimeMillis();
    }
    /**
     * The action to be performed by this timer task.
     */
    public void run()
    {
      long latestCount = exportedCount;
      long deltaCount = (latestCount - previousCount);
      long latestTime = System.currentTimeMillis();
      long deltaTime = latestTime - previousTime;
      if (deltaTime == 0)
      {
        return;
      }
      float rate = 1000f*deltaCount / deltaTime;
      Message message =
          INFO_JEB_EXPORT_PROGRESS_REPORT.get(latestCount, skippedCount, rate);
      logError(message);
      previousCount = latestCount;
      previousTime = latestTime;
    }
  };
}
opends/src/server/org/opends/server/replication/server/ReplicationServer.java
@@ -43,6 +43,7 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
@@ -940,4 +941,17 @@
  {
    // Nothing is needed at the moment
  }
  /**
   * Returns an iterator on the list of replicationCache.
   * Returns null if none.
   * @return the iterator.
   */
  public Iterator<ReplicationCache> getCacheIterator()
  {
    if (!baseDNs.isEmpty())
      return baseDNs.values().iterator();
    else
      return null;
  }
}
opends/src/server/org/opends/server/replication/server/ServerWriter.java
@@ -122,7 +122,7 @@
            "In " + replicationCache.getReplicationServer().
              getMonitorInstanceName() +
            ", writer to " + this.handler.getMonitorInstanceName() +
            " publishes" + update.toString() +
            " publishes msg=" + update.toString() +
            " refgenId=" + referenceGenerationId +
            " server=" + handler.getServerId() +
            " generationId=" + handler.getGenerationId());
opends/tests/unit-tests-testng/src/server/org/opends/server/replication/ReplicationTestCase.java
@@ -855,8 +855,9 @@
        {
          fail("No log messages were written to the task entry on a failed task");
        }
        else
        {
      }
      if (logMessages.size() != 0)
      {
          TRACER.debugInfo(logMessages.get(0));
          if (expectedMessage != null)
          {
@@ -864,7 +865,6 @@
            assertTrue(logMessages.get(0).indexOf(
                expectedMessage.toString())>0);
          }
        }
      }
      assertEquals(taskState, expectedTaskState, "Task State:" + taskState +
opends/tests/unit-tests-testng/src/server/org/opends/server/replication/server/ReplicationServerTest.java
@@ -26,13 +26,12 @@
 */
package org.opends.server.replication.server;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.fail;
import static org.opends.server.loggers.debug.DebugLogger.debugEnabled;
import static org.opends.server.loggers.debug.DebugLogger.getTracer;
import static org.opends.server.replication.protocol.OperationContext.*;
import static org.opends.server.replication.protocol.OperationContext.SYNCHROCONTEXT;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.fail;
import java.io.File;
import java.net.InetAddress;
@@ -54,14 +53,27 @@
import org.opends.server.replication.common.ChangeNumberGenerator;
import org.opends.server.replication.common.ServerState;
import org.opends.server.replication.plugin.ReplicationBroker;
import org.opends.server.replication.protocol.*;
import org.opends.server.replication.protocol.AddMsg;
import org.opends.server.replication.protocol.DeleteMsg;
import org.opends.server.replication.protocol.ModifyDNMsg;
import org.opends.server.replication.protocol.ModifyDnContext;
import org.opends.server.replication.protocol.ModifyMsg;
import org.opends.server.replication.protocol.ProtocolSession;
import org.opends.server.replication.protocol.ProtocolVersion;
import org.opends.server.replication.protocol.ReplServerStartMessage;
import org.opends.server.replication.protocol.ReplSessionSecurity;
import org.opends.server.replication.protocol.ReplicationMessage;
import org.opends.server.replication.protocol.ServerStartMessage;
import org.opends.server.replication.protocol.UpdateMessage;
import org.opends.server.replication.protocol.WindowMessage;
import org.opends.server.replication.protocol.WindowProbe;
import org.opends.server.types.Attribute;
import org.opends.server.types.DN;
import org.opends.server.types.DirectoryConfig;
import org.opends.server.types.Entry;
import org.opends.server.types.Modification;
import org.opends.server.types.ModificationType;
import org.opends.server.types.RDN;
import org.opends.server.types.DirectoryConfig;
import org.opends.server.types.ResultCode;
import org.opends.server.util.TimeThread;
import org.opends.server.workflowelement.localbackend.LocalBackendModifyDNOperation;
@@ -995,6 +1007,56 @@
     debugInfo("Ending   backupRestore");
   }
   /*
    * Test export of the Replication server backend
    * - Creates 2 brokers connecting to the replication for 2 differents baseDN
    * - Make these brokers publish changes to the replication server
    * - Launch a full export
    * - Launch a partial export on one of the 2 domains
    */
    @Test(enabled=true)
    public void exportBackend() throws Exception
    {
      debugInfo("Starting exportBackend");
      ReplicationBroker server1 = null;
      ReplicationBroker server2 = null;
      try {
        server1 = openReplicationSession(
            DN.decode("dc=example,dc=com"), (short) 1, 100, replicationServerPort,
            1000, true);
        server2 = openReplicationSession(
            DN.decode("dc=example2,dc=com"), (short) 2, 100, replicationServerPort,
            1000, true);
      }
      catch(Exception e) {}
      debugInfo("Publish changes");
      List<UpdateMessage> msgs = createChanges("dc=example,dc=com", (short)1);
      for(UpdateMessage msg : msgs )
      {
        server1.publish(msg);
      }
      List<UpdateMessage> msgs2 = createChanges("dc=example2,dc=com", (short)2);
      for(UpdateMessage msg : msgs2 )
      {
        server2.publish(msg);
      }
      debugInfo("Export all");
      Entry exportTask = createExportAllTask();
      addTask(exportTask, ResultCode.SUCCESS, null);
      waitTaskState(exportTask, TaskState.COMPLETED_SUCCESSFULLY, null);
      debugInfo("Export domain");
      exportTask = createExportDomainTask("dc=example2,dc=com");
      addTask(exportTask, ResultCode.SUCCESS, null);
      waitTaskState(exportTask, TaskState.COMPLETED_SUCCESSFULLY, null);
      debugInfo("Ending export");
    }
   private Entry createBackupTask()
   throws Exception
   {
@@ -1022,4 +1084,118 @@
     "ds-backup-directory-path: bak" + File.separator +
                        "replicationChanges");
   }
   private Entry createExportAllTask()
   throws Exception
   {
     String buildRoot = System.getProperty(TestCaseUtils.PROPERTY_BUILD_ROOT);
     String path = buildRoot + File.separator + "build" +
                   File.separator + "unit-tests" + File.separator +
                   "package"+ File.separator + "exportLDIF.ldif";
     return TestCaseUtils.makeEntry(
     "dn: ds-task-id=" + UUID.randomUUID() + ",cn=Scheduled Tasks,cn=Tasks",
     "objectclass: top",
     "objectclass: ds-task",
     "objectclass: ds-task-export",
     "ds-task-class-name: org.opends.server.tasks.ExportTask",
     "ds-task-export-ldif-file: " + path,
     "ds-task-export-backend-id: replicationChanges",
     "ds-task-export-include-branch: dc=replicationChanges");
   }
   private Entry createExportDomainTask(String suffix)
   throws Exception
   {
     String root = suffix.substring(suffix.indexOf('=')+1, suffix.indexOf(','));
     String buildRoot = System.getProperty(TestCaseUtils.PROPERTY_BUILD_ROOT);
     String path = buildRoot + File.separator + "build" +
                   File.separator + "unit-tests" + File.separator +
                   "package"+ File.separator + "exportLDIF" + root +".ldif";
     return TestCaseUtils.makeEntry(
     "dn: ds-task-id=" + UUID.randomUUID() + ",cn=Scheduled Tasks,cn=Tasks",
     "objectclass: top",
     "objectclass: ds-task",
     "objectclass: ds-task-export",
     "ds-task-class-name: org.opends.server.tasks.ExportTask",
     "ds-task-export-ldif-file: " + path,
     "ds-task-export-backend-id: replicationChanges",
     "ds-task-export-include-branch: "+suffix+",dc=replicationChanges");
   }
   private List<UpdateMessage> createChanges(String suffix, short serverId)
   {
     List<UpdateMessage> l = new ArrayList<UpdateMessage>();
     long time = TimeThread.getTime();
     int ts = 1;
     ChangeNumber cn;
     try
     {
       String user1entryUUID = "33333333-3333-3333-3333-333333333333";
       String baseUUID       = "22222222-2222-2222-2222-222222222222";
       // - Add
       String lentry = new String("dn: "+suffix+"\n"
           + "objectClass: top\n"
           + "objectClass: domain\n"
           + "entryUUID: 11111111-1111-1111-1111-111111111111\n");
       Entry entry = TestCaseUtils.entryFromLdifString(lentry);
       cn = new ChangeNumber(time, ts++, serverId);
       AddMsg addMsg = new AddMsg(cn, "o=test,"+suffix,
           user1entryUUID, baseUUID, entry.getObjectClassAttribute(), entry
           .getAttributes(), new ArrayList<Attribute>());
       l.add(addMsg);
       // - Add
       String luentry = new String(
             "dn: uid=new person,ou=People,"+suffix+"\n"
           + "objectClass: top\n"
           + "objectclass: person\n"
           + "objectclass: organizationalPerson\n"
           + "objectclass: inetOrgPerson\n"
           + "cn: Fiona Jensen\n"
           + "sn: Jensen\n"
           + "uid: new person\n"
           + "telephonenumber: +1 408 555 1212\n"
           + "entryUUID: " + user1entryUUID +"\n");
       Entry uentry = TestCaseUtils.entryFromLdifString(luentry);
       cn = new ChangeNumber(time, ts++, serverId);
       AddMsg addMsg2 = new AddMsg(
           cn,
           "uid=new person,ou=People,"+suffix,
           user1entryUUID,
           baseUUID,
           uentry.getObjectClassAttribute(),
           uentry.getAttributes(),
           new ArrayList<Attribute>());
       l.add(addMsg2);
       // - Modify
       Attribute attr1 = new Attribute("description", "new value");
       Modification mod1 = new Modification(ModificationType.REPLACE, attr1);
       List<Modification> mods = new ArrayList<Modification>();
       mods.add(mod1);
       cn = new ChangeNumber(time, ts++, serverId);
       DN dn = DN.decode("o=test,"+suffix);
       ModifyMsg modMsg = new ModifyMsg(cn, dn,
           mods, "fakeuniqueid");
       l.add(modMsg);
       // Modify DN
       cn = new ChangeNumber(time, ts++, serverId);
       ModifyDNMsg  modDnMsg = new ModifyDNMsg(
           "uid=new person,ou=People,"+suffix, cn,
           user1entryUUID, baseUUID, false,
           "uid=wrong, ou=people,"+suffix,
       "uid=newrdn");
       l.add(modDnMsg);
       // Del
       cn = new ChangeNumber(time, ts++, serverId);
       DeleteMsg delMsg = new DeleteMsg("o=test,"+suffix, cn, "uid");
       l.add(delMsg);
     }
     catch(Exception e) {};
     return l;
   }
}