From 81baae45e3f229f5d37224ff8d078dd158ba21e0 Mon Sep 17 00:00:00 2001
From: Jean-Noel Rouvignac <jean-noel.rouvignac@forgerock.com>
Date: Mon, 25 Feb 2013 09:48:27 +0000
Subject: [PATCH] OPENDJ-390 ConcurrentModificationException during backup all
---
opends/src/server/org/opends/server/types/Entry.java | 617 +++++++++++++++++++++++++------------------------------
1 files changed, 277 insertions(+), 340 deletions(-)
diff --git a/opends/src/server/org/opends/server/types/Entry.java b/opends/src/server/org/opends/server/types/Entry.java
index 5fa305f..9fe5631 100644
--- a/opends/src/server/org/opends/server/types/Entry.java
+++ b/opends/src/server/org/opends/server/types/Entry.java
@@ -23,12 +23,9 @@
*
*
* Copyright 2006-2010 Sun Microsystems, Inc.
- * Portions copyright 2011-2012 ForgeRock AS
+ * Portions copyright 2011-2013 ForgeRock AS
*/
package org.opends.server.types;
-import org.opends.messages.Message;
-import org.opends.messages.MessageBuilder;
-
import java.io.BufferedWriter;
import java.io.IOException;
@@ -45,6 +42,8 @@
import java.util.Set;
import java.util.concurrent.locks.Lock;
+import org.opends.messages.Message;
+import org.opends.messages.MessageBuilder;
import org.opends.server.api.AttributeValueDecoder;
import org.opends.server.api.CompressedSchema;
import org.opends.server.api.ProtocolElement;
@@ -52,20 +51,21 @@
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.PluginConfigManager;
import org.opends.server.core.SubentryManager;
-import org.opends.server.util.LDIFException;
-
-import static org.opends.server.config.ConfigConstants.*;
-import static org.opends.server.loggers.debug.DebugLogger.*;
import org.opends.server.loggers.debug.DebugTracer;
-import static org.opends.server.loggers.ErrorLogger.*;
+import org.opends.server.types.SubEntry.CollectiveConflictBehavior;
+import org.opends.server.util.LDIFException;
+import org.opends.server.util.LDIFWriter;
+
import static org.opends.messages.CoreMessages.*;
import static org.opends.messages.UtilityMessages.*;
+import static org.opends.server.config.ConfigConstants.*;
+import static org.opends.server.loggers.ErrorLogger.*;
+import static org.opends.server.loggers.debug.DebugLogger.*;
import static org.opends.server.util.LDIFWriter.*;
import static org.opends.server.util.ServerConstants.*;
import static org.opends.server.util.StaticUtils.*;
-
/**
* This class defines a data structure for a Directory Server entry.
* It includes a DN and a set of attributes.
@@ -103,8 +103,12 @@
// The set of user attributes for this entry.
private Map<AttributeType,List<Attribute>> userAttributes;
- // The set of suppressed real attributes for this entry.
- private Map<AttributeType,List<Attribute>> suppressedAttributes;
+ /**
+ * The set of suppressed real attributes for this entry. It contains real
+ * attributes that have been overridden by virtual attributes.
+ */
+ private final Map<AttributeType, List<Attribute>> suppressedAttributes =
+ new LinkedHashMap<AttributeType, List<Attribute>>();
// The set of objectclasses for this entry.
private Map<ObjectClass,String> objectClasses;
@@ -148,8 +152,6 @@
{
attachment = null;
schema = DirectoryServer.getSchema();
- suppressedAttributes =
- new LinkedHashMap<AttributeType,List<Attribute>>();
if (dn == null)
{
@@ -3830,85 +3832,77 @@
{
// There is a conflict with an existing operational
// attribute.
- if (attrList.get(0).isVirtual())
- {
- // The existing attribute is already virtual,
- // so we've got a different conflict, but
- // we'll let the first win.
- // FIXME -- Should we handle this differently?
- continue;
- }
-
- // The conflict is with a real attribute. See what the
- // conflict behavior is and figure out how to handle it.
- switch (subEntry.getConflictBehavior())
- {
- case REAL_OVERRIDES_VIRTUAL:
- // We don't need to update the entry because
- // the real attribute will take precedence.
- break;
-
- case VIRTUAL_OVERRIDES_REAL:
- // We need to move the real attribute to the
- // suppressed list and replace it with the
- // virtual attribute.
- suppressedAttributes.put(attributeType, attrList);
- attrList = new LinkedList<Attribute>();
- attrList.add(collectiveAttr);
- operationalAttributes.put(attributeType, attrList);
- break;
-
- case MERGE_REAL_AND_VIRTUAL:
- // We need to add the virtual attribute to the
- // list and keep the existing real attribute(s).
- attrList.add(collectiveAttr);
- break;
- }
+ resolveCollectiveConflict(subEntry.getConflictBehavior(),
+ collectiveAttr, attrList, operationalAttributes,
+ attributeType);
}
}
else
{
// There is a conflict with an existing user attribute.
- if (attrList.get(0).isVirtual())
- {
- // The existing attribute is already virtual,
- // so we've got a different conflict, but
- // we'll let the first win.
- // FIXME -- Should we handle this differently?
- continue;
- }
-
- // The conflict is with a real attribute. See what the
- // conflict behavior is and figure out how to handle it.
- switch (subEntry.getConflictBehavior())
- {
- case REAL_OVERRIDES_VIRTUAL:
- // We don't need to update the entry because the real
- // attribute will take precedence.
- break;
-
- case VIRTUAL_OVERRIDES_REAL:
- // We need to move the real attribute to the
- // suppressed list and replace it with the
- // virtual attribute.
- suppressedAttributes.put(attributeType, attrList);
- attrList = new LinkedList<Attribute>();
- attrList.add(collectiveAttr);
- userAttributes.put(attributeType, attrList);
- break;
-
- case MERGE_REAL_AND_VIRTUAL:
- // We need to add the virtual attribute to the
- // list and keep the existing real attribute(s).
- attrList.add(collectiveAttr);
- break;
- }
+ resolveCollectiveConflict(subEntry.getConflictBehavior(),
+ collectiveAttr, attrList, userAttributes, attributeType);
}
}
}
}
}
+ /**
+ * Resolves a conflict arising with a collective attribute.
+ *
+ * @param conflictBehavior
+ * the behavior of the conflict
+ * @param collectiveAttr
+ * the attribute in conflict
+ * @param attrList
+ * the List of attribute where to resolve the conflict
+ * @param attributes
+ * the Map of attributes where to solve the conflict
+ * @param attributeType
+ * the attribute type used with the Map
+ */
+ private void resolveCollectiveConflict(
+ CollectiveConflictBehavior conflictBehavior, Attribute collectiveAttr,
+ List<Attribute> attrList, Map<AttributeType, List<Attribute>> attributes,
+ AttributeType attributeType)
+ {
+ if (attrList.get(0).isVirtual())
+ {
+ // The existing attribute is already virtual,
+ // so we've got a different conflict, but
+ // we'll let the first win.
+ // FIXME -- Should we handle this differently?
+ return;
+ }
+
+ // The conflict is with a real attribute. See what the
+ // conflict behavior is and figure out how to handle it.
+ switch (conflictBehavior)
+ {
+ case REAL_OVERRIDES_VIRTUAL:
+ // We don't need to update the entry because the real attribute will take
+ // precedence.
+ break;
+
+ case VIRTUAL_OVERRIDES_REAL:
+ // We need to move the real attribute to the
+ // suppressed list and replace it with the
+ // virtual attribute.
+ suppressedAttributes.put(attributeType, attrList);
+ attrList = new LinkedList<Attribute>();
+ attrList.add(collectiveAttr);
+ attributes.put(attributeType, attrList);
+ break;
+
+ case MERGE_REAL_AND_VIRTUAL:
+ // We need to add the virtual attribute to the
+ // list and keep the existing real attribute(s).
+ attrList.add(collectiveAttr);
+ break;
+ }
+ }
+
/**
@@ -3947,79 +3941,14 @@
{
// There is a conflict with an existing operational
// attribute.
- if (attrList.get(0).isVirtual())
- {
- // The existing attribute is already virtual, so we've got
- // a different conflict, but we'll let the first win.
- // FIXME -- Should we handle this differently?
- continue;
- }
-
- // The conflict is with a real attribute. See what the
- // conflict behavior is and figure out how to handle it.
- switch (rule.getConflictBehavior())
- {
- case REAL_OVERRIDES_VIRTUAL:
- // We don't need to update the entry because the real
- // attribute will take precedence.
- break;
-
- case VIRTUAL_OVERRIDES_REAL:
- // We need to move the real attribute to the suppressed
- // list and replace it with the virtual attribute.
- suppressedAttributes.put(attributeType, attrList);
- attrList = new LinkedList<Attribute>();
- attrList.add(new VirtualAttribute(attributeType, this,
- rule));
- operationalAttributes.put(attributeType, attrList);
- break;
-
- case MERGE_REAL_AND_VIRTUAL:
- // We need to add the virtual attribute to the list and
- // keep the existing real attribute(s).
- attrList.add(new VirtualAttribute(attributeType, this,
- rule));
- break;
- }
+ resolveVirtualConflict(rule, attrList, operationalAttributes,
+ attributeType);
}
}
else
{
// There is a conflict with an existing user attribute.
- if (attrList.get(0).isVirtual())
- {
- // The existing attribute is already virtual, so we've got
- // a different conflict, but we'll let the first win.
- // FIXME -- Should we handle this differently?
- continue;
- }
-
- // The conflict is with a real attribute. See what the
- // conflict behavior is and figure out how to handle it.
- switch (rule.getConflictBehavior())
- {
- case REAL_OVERRIDES_VIRTUAL:
- // We don't need to update the entry because the real
- // attribute will take precedence.
- break;
-
- case VIRTUAL_OVERRIDES_REAL:
- // We need to move the real attribute to the suppressed
- // list and replace it with the virtual attribute.
- suppressedAttributes.put(attributeType, attrList);
- attrList = new LinkedList<Attribute>();
- attrList.add(new VirtualAttribute(attributeType, this,
- rule));
- userAttributes.put(attributeType, attrList);
- break;
-
- case MERGE_REAL_AND_VIRTUAL:
- // We need to add the virtual attribute to the list and
- // keep the existing real attribute(s).
- attrList.add(new VirtualAttribute(attributeType, this,
- rule));
- break;
- }
+ resolveVirtualConflict(rule, attrList, userAttributes, attributeType);
}
}
@@ -4027,6 +3956,55 @@
processCollectiveAttributes();
}
+ /**
+ * Resolves a conflict arising with a virtual attribute.
+ *
+ * @param rule
+ * the VirtualAttributeRule in conflict
+ * @param attrList
+ * the List of attribute where to resolve the conflict
+ * @param attributes
+ * the Map of attribute where to resolve the conflict
+ * @param attributeType
+ * the attribute type used with the Map
+ */
+ private void resolveVirtualConflict(VirtualAttributeRule rule,
+ List<Attribute> attrList, Map<AttributeType, List<Attribute>> attributes,
+ AttributeType attributeType)
+ {
+ if (attrList.get(0).isVirtual())
+ {
+ // The existing attribute is already virtual, so we've got
+ // a different conflict, but we'll let the first win.
+ // FIXME -- Should we handle this differently?
+ return;
+ }
+
+ // The conflict is with a real attribute. See what the
+ // conflict behavior is and figure out how to handle it.
+ switch (rule.getConflictBehavior())
+ {
+ case REAL_OVERRIDES_VIRTUAL:
+ // We don't need to update the entry because the real
+ // attribute will take precedence.
+ break;
+
+ case VIRTUAL_OVERRIDES_REAL:
+ // We need to move the real attribute to the suppressed
+ // list and replace it with the virtual attribute.
+ suppressedAttributes.put(attributeType, attrList);
+ attrList = new LinkedList<Attribute>();
+ attrList.add(new VirtualAttribute(attributeType, this, rule));
+ attributes.put(attributeType, attrList);
+ break;
+
+ case MERGE_REAL_AND_VIRTUAL:
+ // We need to add the virtual attribute to the list and
+ // keep the existing real attribute(s).
+ attrList.add(new VirtualAttribute(attributeType, this, rule));
+ break;
+ }
+ }
/**
@@ -4580,55 +4558,47 @@
// Next, add the set of user attributes.
- for (List<Attribute> attrList : userAttributes.values())
- {
- for (Attribute a : attrList)
- {
- StringBuilder attrName = new StringBuilder(a.getName());
- for (String o : a.getOptions())
- {
- attrName.append(";");
- attrName.append(o);
- }
-
- for (AttributeValue v : a)
- {
- StringBuilder attrLine = new StringBuilder();
- attrLine.append(attrName);
- appendLDIFSeparatorAndValue(attrLine, v.getValue());
- ldifLines.add(attrLine);
- }
- }
- }
-
+ addLinesForAttributes(ldifLines, userAttributes);
// Finally, add the set of operational attributes.
- for (List<Attribute> attrList : operationalAttributes.values())
- {
- for (Attribute a : attrList)
- {
- StringBuilder attrName = new StringBuilder(a.getName());
- for (String o : a.getOptions())
- {
- attrName.append(";");
- attrName.append(o);
- }
-
- for (AttributeValue v : a)
- {
- StringBuilder attrLine = new StringBuilder();
- attrLine.append(attrName);
- appendLDIFSeparatorAndValue(attrLine, v.getValue());
- ldifLines.add(attrLine);
- }
- }
- }
-
+ addLinesForAttributes(ldifLines, operationalAttributes);
return ldifLines;
}
+ /**
+ * Add LDIF lines for each passed in attributes.
+ *
+ * @param ldifLines
+ * the List where to add the LDIF lines
+ * @param attributes
+ * the List of attributes to convert into LDIf lines
+ */
+ private void addLinesForAttributes(List<StringBuilder> ldifLines,
+ Map<AttributeType, List<Attribute>> attributes)
+ {
+ for (List<Attribute> attrList : attributes.values())
+ {
+ for (Attribute a : attrList)
+ {
+ StringBuilder attrName = new StringBuilder(a.getName());
+ for (String o : a.getOptions())
+ {
+ attrName.append(";");
+ attrName.append(o);
+ }
+
+ for (AttributeValue v : a)
+ {
+ StringBuilder attrLine = new StringBuilder(attrName);
+ appendLDIFSeparatorAndValue(attrLine, v.getValue());
+ ldifLines.add(attrLine);
+ }
+ }
+ }
+ }
+
/**
* Writes this entry in LDIF form according to the provided
@@ -4703,7 +4673,7 @@
dnLine.append("dn");
appendLDIFSeparatorAndValue(dnLine,
ByteString.valueOf(dn.toString()));
- writeLDIFLine(dnLine, writer, wrapLines, wrapColumn);
+ LDIFWriter.writeLDIFLine(dnLine, writer, wrapLines, wrapColumn);
// Next, the set of objectclasses.
@@ -4713,7 +4683,7 @@
if (typesOnly)
{
StringBuilder ocLine = new StringBuilder("objectClass:");
- writeLDIFLine(ocLine, writer, wrapLines, wrapColumn);
+ LDIFWriter.writeLDIFLine(ocLine, writer, wrapLines, wrapColumn);
}
else
{
@@ -4722,7 +4692,7 @@
StringBuilder ocLine = new StringBuilder();
ocLine.append("objectClass: ");
ocLine.append(s);
- writeLDIFLine(ocLine, writer, wrapLines, wrapColumn);
+ LDIFWriter.writeLDIFLine(ocLine, writer, wrapLines, wrapColumn);
}
}
}
@@ -4738,125 +4708,15 @@
// Now the set of user attributes.
- for (AttributeType attrType : userAttributes.keySet())
- {
- if (exportConfig.includeAttribute(attrType))
- {
- List<Attribute> attrList = userAttributes.get(attrType);
- for (Attribute a : attrList)
- {
- if (a.isVirtual() &&
- (! exportConfig.includeVirtualAttributes()))
- {
- continue;
- }
-
- if (typesOnly)
- {
- StringBuilder attrName = new StringBuilder(a.getName());
- for (String o : a.getOptions())
- {
- attrName.append(";");
- attrName.append(o);
- }
- attrName.append(":");
-
- writeLDIFLine(attrName, writer, wrapLines, wrapColumn);
- }
- else
- {
- StringBuilder attrName = new StringBuilder(a.getName());
- for (String o : a.getOptions())
- {
- attrName.append(";");
- attrName.append(o);
- }
-
- for (AttributeValue v : a)
- {
- StringBuilder attrLine = new StringBuilder();
- attrLine.append(attrName);
- appendLDIFSeparatorAndValue(attrLine,
- v.getValue());
- writeLDIFLine(attrLine, writer, wrapLines, wrapColumn);
- }
- }
- }
- }
- else
- {
- if (debugEnabled())
- {
- TRACER.debugVerbose(
- "Skipping user attribute %s for entry %s because of " +
- "the export configuration.",
- attrType.getNameOrOID(), String.valueOf(dn));
- }
- }
- }
+ writeLDIFLines(userAttributes, typesOnly, "user", exportConfig, writer,
+ wrapColumn, wrapLines);
// Next, the set of operational attributes.
if (exportConfig.includeOperationalAttributes())
{
- for (AttributeType attrType : operationalAttributes.keySet())
- {
- if (exportConfig.includeAttribute(attrType))
- {
- List<Attribute> attrList =
- operationalAttributes.get(attrType);
- for (Attribute a : attrList)
- {
- if (a.isVirtual() &&
- (! exportConfig.includeVirtualAttributes()))
- {
- continue;
- }
-
- if (typesOnly)
- {
- StringBuilder attrName = new StringBuilder(a.getName());
- for (String o : a.getOptions())
- {
- attrName.append(";");
- attrName.append(o);
- }
- attrName.append(":");
-
- writeLDIFLine(attrName, writer, wrapLines, wrapColumn);
- }
- else
- {
- StringBuilder attrName = new StringBuilder(a.getName());
- for (String o : a.getOptions())
- {
- attrName.append(";");
- attrName.append(o);
- }
-
- for (AttributeValue v : a)
- {
- StringBuilder attrLine = new StringBuilder();
- attrLine.append(attrName);
- appendLDIFSeparatorAndValue(attrLine,
- v.getValue());
- writeLDIFLine(attrLine, writer, wrapLines,
- wrapColumn);
- }
- }
- }
- }
- else
- {
- if (debugEnabled())
- {
- TRACER.debugVerbose(
- "Skipping operational attribute %s for entry %s " +
- "because of the export configuration.",
- attrType.getNameOrOID(), String.valueOf(dn));
- }
- }
- }
+ writeLDIFLines(operationalAttributes, typesOnly, "operational",
+ exportConfig, writer, wrapColumn, wrapLines);
}
else
{
@@ -4881,37 +4741,7 @@
{
for (Attribute a : suppressedAttributes.get(t))
{
- if (typesOnly)
- {
- StringBuilder attrName = new StringBuilder(a.getName());
- for (String o : a.getOptions())
- {
- attrName.append(";");
- attrName.append(o);
- }
- attrName.append(":");
-
- writeLDIFLine(attrName, writer, wrapLines, wrapColumn);
- }
- else
- {
- StringBuilder attrName = new StringBuilder(a.getName());
- for (String o : a.getOptions())
- {
- attrName.append(";");
- attrName.append(o);
- }
-
- for (AttributeValue v : a)
- {
- StringBuilder attrLine = new StringBuilder();
- attrLine.append(attrName);
- appendLDIFSeparatorAndValue(attrLine,
- v.getValue());
- writeLDIFLine(attrLine, writer, wrapLines,
- wrapColumn);
- }
- }
+ writeLDIFLine(a, typesOnly, writer, wrapLines, wrapColumn);
}
}
}
@@ -4926,6 +4756,110 @@
}
+ /**
+ * Writes the provided List of attributes to LDIF using the provided
+ * information.
+ *
+ * @param attributes
+ * the List of attributes to write as LDIF
+ * @param typesOnly
+ * if true, only writes the type information, else writes the type
+ * information and values for the attribute.
+ * @param attributeType
+ * the type of attribute being written to LDIF
+ * @param exportConfig
+ * configures the export to LDIF
+ * @param writer
+ * The writer to which the data should be written. It must not be
+ * <CODE>null</CODE>.
+ * @param wrapLines
+ * Indicates whether to wrap long lines.
+ * @param wrapColumn
+ * The column at which long lines should be wrapped.
+ * @throws IOException
+ * If a problem occurs while writing the information.
+ */
+ private void writeLDIFLines(Map<AttributeType, List<Attribute>> attributes,
+ final boolean typesOnly, String attributeType,
+ LDIFExportConfig exportConfig, BufferedWriter writer, int wrapColumn,
+ boolean wrapLines) throws IOException
+ {
+ for (AttributeType attrType : attributes.keySet())
+ {
+ if (exportConfig.includeAttribute(attrType))
+ {
+ List<Attribute> attrList = attributes.get(attrType);
+ for (Attribute a : attrList)
+ {
+ if (a.isVirtual() &&
+ (! exportConfig.includeVirtualAttributes()))
+ {
+ continue;
+ }
+
+ writeLDIFLine(a, typesOnly, writer, wrapLines, wrapColumn);
+ }
+ }
+ else
+ {
+ if (debugEnabled())
+ {
+ TRACER.debugVerbose("Skipping %s attribute %s for entry %s "
+ + "because of the export configuration.", attributeType, attrType
+ .getNameOrOID(), String.valueOf(dn));
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Writes the provided attribute to LDIF using the provided information.
+ *
+ * @param attribute
+ * the attribute to write to LDIF
+ * @param typesOnly
+ * if true, only writes the type information, else writes the type
+ * information and values for the attribute.
+ * @param writer
+ * The writer to which the data should be written. It must not be
+ * <CODE>null</CODE>.
+ * @param wrapLines
+ * Indicates whether to wrap long lines.
+ * @param wrapColumn
+ * The column at which long lines should be wrapped.
+ * @throws IOException
+ * If a problem occurs while writing the information.
+ */
+ private void writeLDIFLine(Attribute attribute, final boolean typesOnly,
+ BufferedWriter writer, boolean wrapLines, int wrapColumn)
+ throws IOException
+ {
+ StringBuilder attrName = new StringBuilder(attribute.getName());
+ for (String o : attribute.getOptions())
+ {
+ attrName.append(";");
+ attrName.append(o);
+ }
+
+ if (typesOnly)
+ {
+ attrName.append(":");
+
+ LDIFWriter.writeLDIFLine(attrName, writer, wrapLines, wrapColumn);
+ }
+ else
+ {
+ for (AttributeValue v : attribute)
+ {
+ StringBuilder attrLine = new StringBuilder(attrName);
+ appendLDIFSeparatorAndValue(attrLine, v.getValue());
+ LDIFWriter.writeLDIFLine(attrLine, writer, wrapLines, wrapColumn);
+ }
+ }
+ }
+
+
/**
* Retrieves the name of the protocol associated with this protocol
@@ -4934,6 +4868,7 @@
* @return The name of the protocol associated with this protocol
* element.
*/
+ @Override
public String getProtocolElementName()
{
return "Entry";
@@ -5076,6 +5011,7 @@
* @param buffer The buffer into which the string representation
* should be written.
*/
+ @Override
public void toString(StringBuilder buffer)
{
buffer.append(toString());
@@ -5092,6 +5028,7 @@
* @param indent The number of spaces that should be used to
* indent the resulting string representation.
*/
+ @Override
public void toString(StringBuilder buffer, int indent)
{
StringBuilder indentBuf = new StringBuilder(indent);
--
Gitblit v1.10.0