From 4c7d89a5b8f1503bf63988ae13d47d269e1615de Mon Sep 17 00:00:00 2001
From: mrossign <mrossign@localhost>
Date: Fri, 31 Oct 2008 16:15:12 +0000
Subject: [PATCH] Partial fix for #3525: Attribute modifications are not replicated for modDN operations Warning: ModifyDNMsg PDU is updated and modifications are exchanged through the replication network. However at replay time, the moddn operation is re-created with the modifications, but they cannot be replayed at this time: The comment of the addModification() method for ModifyDNOperation states that "This should only be called by pre-operation plugins"
---
opends/src/server/org/opends/server/replication/protocol/ModifyDNMsg.java | 90 ++++++++++++++++++++++++++++++++++++++++++---
1 files changed, 84 insertions(+), 6 deletions(-)
diff --git a/opends/src/server/org/opends/server/replication/protocol/ModifyDNMsg.java b/opends/src/server/org/opends/server/replication/protocol/ModifyDNMsg.java
index 1a3cd39..c146b2a 100644
--- a/opends/src/server/org/opends/server/replication/protocol/ModifyDNMsg.java
+++ b/opends/src/server/org/opends/server/replication/protocol/ModifyDNMsg.java
@@ -29,22 +29,29 @@
import static org.opends.server.replication.protocol.OperationContext.*;
import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.List;
import java.util.zip.DataFormatException;
import org.opends.server.core.ModifyDNOperationBasis;
+import org.opends.server.protocols.asn1.ASN1Element;
+import org.opends.server.protocols.asn1.ASN1Exception;
import org.opends.server.protocols.asn1.ASN1OctetString;
import org.opends.server.protocols.internal.InternalClientConnection;
+import org.opends.server.protocols.ldap.LDAPModification;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.types.AbstractOperation;
import org.opends.server.types.DN;
import org.opends.server.types.DirectoryException;
+import org.opends.server.types.LDAPException;
+import org.opends.server.types.Modification;
import org.opends.server.types.RDN;
import org.opends.server.types.operation.PostOperationModifyDNOperation;
/**
* Message used to send Modify DN information.
*/
-public class ModifyDNMsg extends UpdateMsg
+public class ModifyDNMsg extends ModifyCommonMsg
{
private String newRDN;
private String newSuperior;
@@ -61,6 +68,8 @@
super((OperationContext) operation.getAttachment(SYNCHROCONTEXT),
operation.getRawEntryDN().stringValue());
+ encodedMods = modsToByte(operation.getModifications());
+
ModifyDnContext ctx =
(ModifyDnContext) operation.getAttachment(SYNCHROCONTEXT);
newSuperiorId = ctx.getNewParentId();
@@ -74,17 +83,19 @@
}
/**
- * construct a new Modify DN message.
+ * Construct a new Modify DN message (no mods).
+ * Note: Keep this constructor version to support already written tests, not
+ * using mods.
*
* @param dn The dn to use for building the message.
* @param changeNumber The changeNumberto use for building the message.
- * @param uid The unique id to use for building the message.
+ * @param uid The unique id to use for building the message.
* @param newParentUid The new parent unique id to use for building
* the message.
* @param deleteOldRdn boolean indicating if old rdn must be deleted to use
* for building the message.
- * @param newSuperior The new Superior entry to use for building the message.
- * @param newRDN The new Rdn to use for building the message.
+ * @param newSuperior The new Superior entry to use for building the message.
+ * @param newRDN The new Rdn to use for building the message.
*/
public ModifyDNMsg(String dn, ChangeNumber changeNumber, String uid,
String newParentUid, boolean deleteOldRdn,
@@ -100,6 +111,29 @@
}
/**
+ * Construct a new Modify DN message (with mods).
+ *
+ * @param dn The dn to use for building the message.
+ * @param changeNumber The changeNumberto use for building the message.
+ * @param uid The unique id to use for building the message.
+ * @param newParentUid The new parent unique id to use for building
+ * the message.
+ * @param deleteOldRdn boolean indicating if old rdn must be deleted to use
+ * for building the message.
+ * @param newSuperior The new Superior entry to use for building the message.
+ * @param newRDN The new Rdn to use for building the message.
+ * @param mods The mod of the operation.
+ */
+ public ModifyDNMsg(String dn, ChangeNumber changeNumber, String uid,
+ String newParentUid, boolean deleteOldRdn,
+ String newSuperior, String newRDN, List<Modification> mods)
+ {
+ this(dn, changeNumber, uid, newParentUid, deleteOldRdn, newSuperior,
+ newRDN);
+ this.encodedMods = modsToByte(mods);
+ }
+
+ /**
* Creates a new ModifyDN message from a byte[].
*
* @param in The byte[] from which the operation must be read.
@@ -145,6 +179,33 @@
deleteOldRdn = false;
else
deleteOldRdn = true;
+ pos++;
+
+ // For easiness (no additional method), simply compare PDU type to
+ // know if we have to read the mods of V2
+ if (in[0] == MSG_TYPE_MODIFYDN)
+ {
+ /* Read the mods : all the remaining bytes but the terminating 0 */
+ length = in.length - pos - 1;
+ if (length > 0) // Otherwise, there is only the trailing 0 byte which we
+ // do not need to read
+ {
+ encodedMods = new byte[length];
+ try
+ {
+ System.arraycopy(in, pos, encodedMods, 0, length);
+ } catch (IndexOutOfBoundsException e)
+ {
+ throw new DataFormatException(e.getMessage());
+ } catch (ArrayStoreException e)
+ {
+ throw new DataFormatException(e.getMessage());
+ } catch (NullPointerException e)
+ {
+ throw new DataFormatException(e.getMessage());
+ }
+ }
+ }
}
/**
@@ -153,6 +214,7 @@
@Override
public AbstractOperation createOperation(
InternalClientConnection connection, String newDn)
+ throws LDAPException, ASN1Exception
{
ModifyDNOperationBasis moddn = new ModifyDNOperationBasis(connection,
InternalClientConnection.nextOperationID(),
@@ -160,6 +222,11 @@
new ASN1OctetString(newDn), new ASN1OctetString(newRDN),
deleteOldRdn,
(newSuperior == null ? null : new ASN1OctetString(newSuperior)));
+
+ ArrayList<ASN1Element> mods = ASN1Element.decodeElements(encodedMods);
+ for (ASN1Element elem : mods)
+ moddn.addModification(LDAPModification.decode(elem).toModification());
+
ModifyDnContext ctx = new ModifyDnContext(getChangeNumber(), getUniqueId(),
newSuperiorId);
moddn.setAttachment(SYNCHROCONTEXT, ctx);
@@ -194,6 +261,8 @@
else
length += 1;
+ length += encodedMods.length + 1;
+
byte[] resultByteArray = encodeHeader(MSG_TYPE_MODIFYDN, length);
int pos = resultByteArray.length - length;
@@ -222,6 +291,15 @@
else
resultByteArray[pos++] = 0;
+ /* add the mods */
+ if (encodedMods.length > 0)
+ {
+ pos = resultByteArray.length - (encodedMods.length + 1);
+ addByteArray(encodedMods, resultByteArray, pos);
+ }
+ else
+ resultByteArray[pos++] = 0;
+
return resultByteArray;
}
@@ -438,7 +516,7 @@
{
// The MODDN message size are mainly dependent on the
// size of the DN. let's assume that they average on 100 bytes
- return 100;
+ return encodedMods.length + 100;
}
/**
--
Gitblit v1.10.0