From d2d863001e51eb3f0f678123b11f9ab1b77ebd6c Mon Sep 17 00:00:00 2001
From: Matthew Swift <matthew.swift@forgerock.com>
Date: Tue, 21 Feb 2012 17:15:54 +0000
Subject: [PATCH] Fix OPENDJ-181: DirectoryException provided value has an invalid length for a UUID
---
opends/tests/unit-tests-testng/src/server/org/opends/server/replication/SchemaReplicationTest.java | 6 ++-
opends/src/server/org/opends/server/replication/plugin/EntryHistorical.java | 94 +++++++++++++++++++++++++++--------------------
opends/src/server/org/opends/server/replication/plugin/LDAPReplicationDomain.java | 2 -
3 files changed, 58 insertions(+), 44 deletions(-)
diff --git a/opends/src/server/org/opends/server/replication/plugin/EntryHistorical.java b/opends/src/server/org/opends/server/replication/plugin/EntryHistorical.java
index 7080249..5ff0c41 100644
--- a/opends/src/server/org/opends/server/replication/plugin/EntryHistorical.java
+++ b/opends/src/server/org/opends/server/replication/plugin/EntryHistorical.java
@@ -29,18 +29,15 @@
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.getBytes;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeMap;
+import java.util.*;
import org.opends.messages.Message;
import org.opends.server.core.DirectoryServer;
+import org.opends.server.loggers.debug.DebugTracer;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.protocol.OperationContext;
import org.opends.server.types.*;
@@ -85,6 +82,13 @@
*/
public static final String ENTRYUUID_ATTRIBUTE_NAME = "entryuuid";
+ /**
+ * The tracer object for the debug logger.
+ */
+ private static final DebugTracer TRACER = getTracer();
+
+
+
/* The delay to purge the historical informations
* This delay indicates the time the domain keeps the historical
* information necessary to solve conflicts.When a change stored in the
@@ -838,14 +842,10 @@
else
{
String uuidString = getEntryUUID(entry);
- if (uuidString != null)
- {
- modifyFakeOperation = new FakeModifyOperation(entry.getDN(),
- cn, uuidString);
-
- modifyFakeOperation.addModification(mod);
- operations.put(histVal.getCn(), modifyFakeOperation);
- }
+ modifyFakeOperation = new FakeModifyOperation(entry.getDN(), cn,
+ uuidString);
+ modifyFakeOperation.addModification(mod);
+ operations.put(histVal.getCn(), modifyFakeOperation);
}
}
}
@@ -874,25 +874,15 @@
*
* @param entry The entry for which the unique id should be returned.
*
- * @return The Unique Id of the entry if it has one. null, otherwise.
+ * @return The Unique Id of the entry, or a fake one if none is found.
*/
public static String getEntryUUID(Entry entry)
{
- String uuidString = null;
AttributeType entryuuidAttrType =
DirectoryServer.getSchema().getAttributeType(ENTRYUUID_ATTRIBUTE_NAME);
List<Attribute> uuidAttrs =
entry.getOperationalAttribute(entryuuidAttrType);
- if (uuidAttrs != null)
- {
- Attribute uuid = uuidAttrs.get(0);
- if (!uuid.isEmpty())
- {
- AttributeValue uuidVal = uuid.iterator().next();
- uuidString = uuidVal.getValue().toString();
- }
- }
- return uuidString;
+ return extractEntryUUID(uuidAttrs, entry.getDN());
}
/**
@@ -905,22 +895,11 @@
*/
public static String getEntryUUID(PreOperationAddOperation op)
{
- String uuidString = null;
Map<AttributeType, List<Attribute>> attrs = op.getOperationalAttributes();
AttributeType entryuuidAttrType =
DirectoryServer.getSchema().getAttributeType(ENTRYUUID_ATTRIBUTE_NAME);
List<Attribute> uuidAttrs = attrs.get(entryuuidAttrType);
-
- if (uuidAttrs != null)
- {
- Attribute uuid = uuidAttrs.get(0);
- if (!uuid.isEmpty())
- {
- AttributeValue uuidVal = uuid.iterator().next();
- uuidString = uuidVal.getValue().toString();
- }
- }
- return uuidString;
+ return extractEntryUUID(uuidAttrs, op.getEntryDN());
}
/**
@@ -969,5 +948,40 @@
{
return this.oldestChangeNumber;
}
+
+
+
+ // Extracts the entryUUID attribute value from the provided list of
+ // attributes. If the attribute is not present one is generated from the DN
+ // using the same algorithm as the entryUUID virtual attribute provider.
+ private static String extractEntryUUID(List<Attribute> entryUUIDAttributes,
+ DN entryDN)
+ {
+ if (entryUUIDAttributes != null)
+ {
+ Attribute uuid = entryUUIDAttributes.get(0);
+ if (!uuid.isEmpty())
+ {
+ AttributeValue uuidVal = uuid.iterator().next();
+ return uuidVal.getValue().toString();
+ }
+ }
+
+ // Generate a fake entryUUID: see OPENDJ-181. In rare pathological cases
+ // an entryUUID attribute may not be present and this causes severe side
+ // effects for replication which requires the attribute to always be
+ // present.
+ if (debugEnabled())
+ {
+ TRACER.debugWarning(
+ "Replication requires an entryUUID attribute in order "
+ + "to perform conflict resolution, but none was "
+ + "found in entry \"%s\": generating virtual entryUUID instead",
+ entryDN);
+ }
+
+ String normDNString = entryDN.toNormalizedString();
+ return UUID.nameUUIDFromBytes(getBytes(normDNString)).toString();
+ }
}
diff --git a/opends/src/server/org/opends/server/replication/plugin/LDAPReplicationDomain.java b/opends/src/server/org/opends/server/replication/plugin/LDAPReplicationDomain.java
index 5382759..cb56540 100644
--- a/opends/src/server/org/opends/server/replication/plugin/LDAPReplicationDomain.java
+++ b/opends/src/server/org/opends/server/replication/plugin/LDAPReplicationDomain.java
@@ -2209,8 +2209,6 @@
ChangeNumber changeNumber = generateChangeNumber(modifyOperation);
String modifiedEntryUUID = EntryHistorical.getEntryUUID(modifiedEntry);
- if (modifiedEntryUUID == null)
- modifiedEntryUUID = modifyOperation.getEntryDN().toString();
ctx = new ModifyContext(changeNumber, modifiedEntryUUID);
modifyOperation.setAttachment(SYNCHROCONTEXT, ctx);
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/SchemaReplicationTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/SchemaReplicationTest.java
index 99145e1..245c47b 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/SchemaReplicationTest.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/SchemaReplicationTest.java
@@ -23,6 +23,7 @@
*
*
* Copyright 2008-2010 Sun Microsystems, Inc.
+ * Portions copyright 2012 ForgeRock AS.
*/
package org.opends.server.replication;
@@ -48,6 +49,7 @@
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.replication.service.ReplicationBroker;
import org.opends.server.replication.common.ChangeNumberGenerator;
+import org.opends.server.replication.plugin.EntryHistorical;
import org.opends.server.replication.protocol.ModifyMsg;
import org.opends.server.replication.protocol.ReplicationMsg;
import org.opends.server.types.Attribute;
@@ -229,8 +231,8 @@
{
ChangeNumberGenerator gen = new ChangeNumberGenerator( 2, 0);
- ModifyMsg modMsg = new ModifyMsg(gen.newChangeNumber(),
- baseDn, rcvdMods, "cn=schema");
+ ModifyMsg modMsg = new ModifyMsg(gen.newChangeNumber(), baseDn, rcvdMods,
+ EntryHistorical.getEntryUUID(DirectoryServer.getEntry(baseDn)));
broker.publish(modMsg);
boolean found = checkEntryHasAttribute(baseDn, "attributetypes",
--
Gitblit v1.10.0