From b5acb25ee2ad9bf8b166b9de1a34e6aab6ea23b7 Mon Sep 17 00:00:00 2001
From: gbellato <gbellato@localhost>
Date: Fri, 01 Sep 2006 12:04:47 +0000
Subject: [PATCH] issue 604 : solve the naming conflict that might happen when several masters are used there are 3 main parts in this commit : - attach the replication context in an OperationContext - if operation replay fails then fix the problem  - in the pre-op checks for conflict and cause failure if necessary most of the time there should be no conflict and the operation should be processed normally

---
 opends/src/server/org/opends/server/synchronization/UpdateMessage.java |  225 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 223 insertions(+), 2 deletions(-)

diff --git a/opends/src/server/org/opends/server/synchronization/UpdateMessage.java b/opends/src/server/org/opends/server/synchronization/UpdateMessage.java
index f7c4bc7..6dc44b6 100644
--- a/opends/src/server/org/opends/server/synchronization/UpdateMessage.java
+++ b/opends/src/server/org/opends/server/synchronization/UpdateMessage.java
@@ -27,8 +27,13 @@
 package org.opends.server.synchronization;
 
 import java.io.Serializable;
+import java.io.UnsupportedEncodingException;
 import java.util.zip.DataFormatException;
 
+import org.opends.server.core.AddOperation;
+import org.opends.server.core.DeleteOperation;
+import org.opends.server.core.ModifyDNOperation;
+import org.opends.server.core.ModifyOperation;
 import org.opends.server.core.Operation;
 import org.opends.server.protocols.asn1.ASN1Exception;
 import org.opends.server.protocols.internal.InternalClientConnection;
@@ -45,7 +50,12 @@
   /**
    * The ChangeNumber of this update.
    */
-  protected ChangeNumber changeNumber;
+  private ChangeNumber changeNumber;
+
+  /**
+   * The DN on which the update was originally done.
+   */
+  private String dn = null;
 
   /**
    * True when the update must use assured replication.
@@ -53,6 +63,83 @@
   private boolean assuredFlag = false;
 
   /**
+   * The UniqueId of the entry that was updated.
+   */
+  private String UniqueId;
+
+  /**
+   * Creates a new UpdateMessage with the given informations.
+   *
+   * @param ctx The Synchronization Context of the operation for which the
+   *            update message must be created,.
+   * @param dn The dn of the entry on which the change
+   *           that caused the creation of this object happened
+   */
+  public UpdateMessage(OperationContext ctx, String dn)
+  {
+    this.changeNumber = ctx.getChangeNumber();
+    this.UniqueId = ctx.getEntryUid();
+    this.dn = dn;
+  }
+
+  /**
+   * Creates a new UpdateMessage from an ecoded byte array.
+   *
+   * @param in The encoded byte array containind the UpdateMessage.
+   * @throws DataFormatException if the encoded byte array is not valid.
+   * @throws UnsupportedEncodingException if UTF-8 is not supprted.
+   */
+  public UpdateMessage(byte[] in) throws DataFormatException,
+                                         UnsupportedEncodingException
+  {
+    /* read the changeNumber */
+    int pos = 1;
+    int length = getNextLength(in, pos);
+    String changenumberStr = new String(in, pos, length, "UTF-8");
+    this.changeNumber = new ChangeNumber(changenumberStr);
+  }
+
+  /**
+   * Generates an Update Message which the provided information.
+   *
+   * @param op The operation fo which the message must be created.
+   * @param isAssured flag indicating if the operation is an assured operation.
+   * @return The generated message.
+   */
+  public static UpdateMessage generateMsg(Operation op, boolean isAssured)
+  {
+    UpdateMessage msg = null;
+    switch (op.getOperationType())
+    {
+    case MODIFY :
+      msg = new ModifyMsg((ModifyOperation) op);
+      if (isAssured)
+        msg.setAssured();
+      break;
+
+    case ADD:
+      msg = new AddMsg((AddOperation) op);
+      if (isAssured)
+        msg.setAssured();
+      break;
+
+    case DELETE :
+      msg = new DeleteMsg((DeleteOperation) op);
+      if (isAssured)
+        msg.setAssured();
+      break;
+
+    case MODIFY_DN :
+      msg = new ModifyDNMsg((ModifyDNOperation) op);
+      if (isAssured)
+        msg.setAssured();
+      break;
+    }
+
+    return msg;
+  }
+
+  /**
    * Get the ChangeNumber from the message.
    * @return the ChangeNumber
    */
@@ -62,6 +149,35 @@
   }
 
   /**
+   * Get the DN on which the operation happened.
+   *
+   * @return The DN on which the operations happened.
+   */
+  public String getDn()
+  {
+    return dn;
+  }
+
+  /**
+   * Set the DN.
+   * @param dn The dn that must now be used for this message.
+   */
+  public void setDn(String dn)
+  {
+    this.dn = dn;
+  }
+
+  /**
+   * Get the Unique Identifier of the entry on which the operation happened.
+   *
+   * @return The Unique Identifier of the entry on which the operation happened.
+   */
+  public String getUniqueId()
+  {
+    return UniqueId;
+  }
+
+  /**
    * Get a boolean indicating if the Update must be processed as an
    * Asynchronous or as an assured synchronization.
    *
@@ -117,10 +233,115 @@
    * @throws  ASN1Exception In case of ASN1 decoding exception.
    * @throws DataFormatException In case of bad msg format.
    */
-  public abstract Operation createOperation(InternalClientConnection conn)
+  public Operation createOperation(InternalClientConnection conn)
+         throws LDAPException, ASN1Exception, DataFormatException
+  {
+    return createOperation(conn, dn);
+  }
+
+
+  /**
+   * Create and Operation from the message using the provided DN.
+   *
+   * @param   conn connection to use when creating the message.
+   * @param   newDn the DN to use when creating the operation.
+   * @return  the created Operation.
+   * @throws  LDAPException In case of LDAP decoding exception.
+   * @throws  ASN1Exception In case of ASN1 decoding exception.
+   * @throws DataFormatException In case of bad msg format.
+   */
+  public abstract Operation createOperation(InternalClientConnection conn,
+                                            String newDn)
          throws LDAPException, ASN1Exception, DataFormatException;
 
+  /**
+   * Encode the common header for all the UpdateMessage.
+   *
+   * @param type the type of UpdateMessage to encode.
+   * @param additionalLength additional length needed to encode the remaining
+   *                         part of the UpdateMessage.
+   * @return a byte array containing the common header and enough space to
+   *         encode the reamining bytes of the UpdateMessage as was specified
+   *         by the additionalLength.
+   *         (byte array length = common header length + additionalLength)
+   * @throws UnsupportedEncodingException if UTF-8 is not supported.
+   */
+  public byte[] encodeHeader(byte type, int additionalLength)
+    throws UnsupportedEncodingException
+  {
+    byte[] byteDn = dn.getBytes("UTF-8");
+    byte[] changeNumberByte =
+      this.getChangeNumber().toString().getBytes("UTF-8");
+    byte[] byteEntryuuid = getUniqueId().getBytes("UTF-8");
 
+    /* The message header is stored in the form :
+     * <operation type>changenumber><dn><entryuuid><change>
+     * the length of result byte array is therefore :
+     *   1 + dn length + 1 + 24 + additional_length
+     */
+    int length = 1 + changeNumberByte.length + 1 + byteDn.length + 1
+                 + byteEntryuuid.length + 1 + additionalLength;
+
+    byte[] encodedMsg = new byte[length];
+
+    /* put the type of the operation */
+    encodedMsg[0] = type;
+    int pos = 1;
+
+    /* put the ChangeNumber */
+    pos = addByteArray(changeNumberByte, encodedMsg, pos);
+
+    /* put the DN and a terminating 0 */
+    pos = addByteArray(byteDn, encodedMsg, pos);
+
+    /* put the entry uuid and a terminating 0 */
+    pos = addByteArray(byteEntryuuid, encodedMsg, pos);
+
+    return encodedMsg;
+  }
+
+  /**
+   * Decode the Header part of this Update Message, and check its type.
+   *
+   * @param type The type of this Update Message.
+   * @param encodedMsg the encoded form of the UpdateMessage.
+   * @return the position at which the remaining part of the message starts.
+   * @throws DataFormatException if the encodedMsg does not contain a valid
+   *         common header.
+   */
+  public int decodeHeader(byte type, byte [] encodedMsg)
+                          throws DataFormatException
+  {
+    /* first byte is the type */
+    if (encodedMsg[0] != type)
+      throw new DataFormatException("byte[] is not a valid msg");
+
+    try
+    {
+      /* read the changeNumber */
+      int pos = 1;
+      int length = getNextLength(encodedMsg, pos);
+      String changenumberStr = new String(encodedMsg, pos, length, "UTF-8");
+      pos += length + 1;
+      changeNumber = new ChangeNumber(changenumberStr);
+
+      /* read the dn */
+      length = getNextLength(encodedMsg, pos);
+      dn = new String(encodedMsg, pos, length, "UTF-8");
+      pos += length + 1;
+
+      /* read the entryuuid */
+      length = getNextLength(encodedMsg, pos);
+      UniqueId = new String(encodedMsg, pos, length, "UTF-8");
+      pos += length + 1;
+
+      return pos;
+    } catch (UnsupportedEncodingException e)
+    {
+      throw new DataFormatException("UTF-8 is not supported by this jvm.");
+    }
+
+  }
   /**
    * {@inheritDoc}
    */

--
Gitblit v1.10.0