From e25d897908d93ab4f9cabadb1029ad3352602d5d Mon Sep 17 00:00:00 2001
From: boli <boli@localhost>
Date: Wed, 31 Oct 2007 22:19:14 +0000
Subject: [PATCH] This set of fixes mainly address the issues where the JE backend does not handle attributes with options and subtypes correctly when they are being indexed. With this fix: - All values of an indexed attribute type will be indexed correctly on modifies, adds, and deletes. - Updates to subordinate types will now update the superior type if its indexed. - Adding and deleting superior attribute types that are not allowed by any object classes (ie. name) will be correctly handled - Deleting all values from an attribute with no options will no longer delete the values from the same attribute but with options.
---
opends/src/server/org/opends/server/backends/jeb/VLVIndex.java | 15
opends/src/server/org/opends/server/backends/jeb/EntryContainer.java | 14
opends/src/server/org/opends/server/backends/jeb/OrderingIndexer.java | 93 ++----
opends/src/server/org/opends/server/types/Entry.java | 243 +++++++++++-----
opends/tests/unit-tests-testng/src/server/org/opends/server/types/EntrySchemaCheckingTestCase.java | 30 ++
opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestEntry.java | 18 +
opends/src/server/org/opends/server/backends/jeb/SubstringIndexer.java | 75 +++-
opends/src/server/org/opends/server/backends/jeb/EqualityIndexer.java | 159 ++--------
opends/src/server/org/opends/server/backends/jeb/ApproximateIndexer.java | 32 ++
opends/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestBackendImpl.java | 154 +++++++++-
opends/src/server/org/opends/server/backends/jeb/PresenceIndexer.java | 19 +
opends/tests/unit-tests-testng/resource/config-changes.ldif | 12
12 files changed, 558 insertions(+), 306 deletions(-)
diff --git a/opends/src/server/org/opends/server/backends/jeb/ApproximateIndexer.java b/opends/src/server/org/opends/server/backends/jeb/ApproximateIndexer.java
index bf42103..84ffd2a 100644
--- a/opends/src/server/org/opends/server/backends/jeb/ApproximateIndexer.java
+++ b/opends/src/server/org/opends/server/backends/jeb/ApproximateIndexer.java
@@ -176,7 +176,37 @@
Set<ASN1OctetString> addKeys,
Set<ASN1OctetString> delKeys)
{
- replaceEntry(txn, oldEntry, newEntry, addKeys, delKeys);
+ List<Attribute> newAttributes = newEntry.getAttribute(attributeType, true);
+ List<Attribute> oldAttributes = oldEntry.getAttribute(attributeType, true);
+ HashSet<AttributeValue> newValues;
+ HashSet<AttributeValue> oldValues;
+
+ if(newAttributes == null)
+ {
+ indexAttribute(oldAttributes, delKeys);
+ }
+ else
+ {
+ if(oldAttributes == null)
+ {
+ indexAttribute(newAttributes, addKeys);
+ }
+ else
+ {
+ HashSet<ASN1OctetString> newKeys =
+ new HashSet<ASN1OctetString>();
+ HashSet<ASN1OctetString> oldKeys =
+ new HashSet<ASN1OctetString>();
+ indexAttribute(newAttributes, newKeys);
+ indexAttribute(oldAttributes, oldKeys);
+
+ addKeys.addAll(newKeys);
+ addKeys.removeAll(oldKeys);
+
+ delKeys.addAll(oldKeys);
+ delKeys.removeAll(newKeys);
+ }
+ }
}
/**
diff --git a/opends/src/server/org/opends/server/backends/jeb/EntryContainer.java b/opends/src/server/org/opends/server/backends/jeb/EntryContainer.java
index 556ebbf..7073463 100644
--- a/opends/src/server/org/opends/server/backends/jeb/EntryContainer.java
+++ b/opends/src/server/org/opends/server/backends/jeb/EntryContainer.java
@@ -3789,15 +3789,27 @@
{
// Check whether any modifications apply to this indexed attribute.
boolean attributeModified = false;
+ AttributeType indexAttributeType = index.getAttributeType();
+ Iterable<AttributeType> subTypes =
+ DirectoryServer.getSchema().getSubTypes(indexAttributeType);
+
for (Modification mod : mods)
{
Attribute modAttr = mod.getAttribute();
AttributeType modAttrType = modAttr.getAttributeType();
- if (modAttrType.equals(index.getAttributeType()))
+ if (modAttrType.equals(indexAttributeType))
{
attributeModified = true;
break;
}
+ for(AttributeType subType : subTypes)
+ {
+ if(modAttrType.equals(subType))
+ {
+ attributeModified = true;
+ break;
+ }
+ }
}
if (attributeModified)
{
diff --git a/opends/src/server/org/opends/server/backends/jeb/EqualityIndexer.java b/opends/src/server/org/opends/server/backends/jeb/EqualityIndexer.java
index 83f2079..e684c0a 100644
--- a/opends/src/server/org/opends/server/backends/jeb/EqualityIndexer.java
+++ b/opends/src/server/org/opends/server/backends/jeb/EqualityIndexer.java
@@ -45,7 +45,6 @@
import java.util.HashSet;
import java.util.List;
import java.util.Set;
-import java.util.ArrayList;
/**
* An implementation of an Indexer for attribute equality.
@@ -191,140 +190,44 @@
Set<ASN1OctetString> delKeys)
throws DatabaseException
{
- // Optimize for the case where there are no attribute options
- // involved and only simple addition and deletion of individual values.
- // An issue with attribute options is that the values can not be assumed
- // to be unique.
+ List<Attribute> newAttributes = newEntry.getAttribute(attributeType, true);
+ List<Attribute> oldAttributes = oldEntry.getAttribute(attributeType, true);
+ HashSet<AttributeValue> newValues;
+ HashSet<AttributeValue> oldValues;
- List<Attribute> beforeList;
- List<Attribute> afterList;
- beforeList = oldEntry.getAttribute(attributeType);
- afterList = newEntry.getAttribute(attributeType);
-
- boolean hasOptions = false;
-
- if (beforeList != null)
+ if(newAttributes == null)
{
- for (Attribute a : beforeList)
- {
- if (a.hasOptions())
- {
- hasOptions = true;
- break;
- }
- }
- }
-
- if (afterList != null)
- {
- for (Attribute a : afterList)
- {
- if (a.hasOptions())
- {
- hasOptions = true;
- break;
- }
- }
- }
-
- boolean hasOnlySimpleMods = true;
- List<Modification> simpleMods = new ArrayList<Modification>();
- for (Modification mod : mods)
- {
- Attribute modAttr = mod.getAttribute();
- AttributeType modAttrType = modAttr.getAttributeType();
- if (modAttrType.equals(attributeType))
- {
- if (modAttr.hasOptions())
- {
- hasOptions = true;
- }
- switch (mod.getModificationType())
- {
- case ADD:
- simpleMods.add(mod);
- break;
-
- case DELETE:
- if (!modAttr.hasValue())
- {
- hasOnlySimpleMods = false;
- }
- else
- {
- simpleMods.add(mod);
- }
- break;
-
- default:
- hasOnlySimpleMods = false;
- break;
- }
- }
- }
-
- if (hasOnlySimpleMods && !hasOptions)
- {
- // This is the optimized case where there are no attribute options
- // involved and only simple addition and deletion of individual values.
- // It should be efficient for adding and/or deleting a few values of an
- // attribute with lots of values.
- for (Modification mod : simpleMods)
- {
- Set<AttributeValue> values = mod.getAttribute().getValues();
- Set<ASN1OctetString> keys =
- new HashSet<ASN1OctetString>(values.size());
- indexValues(values, keys);
-
- switch (mod.getModificationType())
- {
- case ADD:
- for (ASN1OctetString key : keys)
- {
- if (delKeys.contains(key))
- {
- delKeys.remove(key);
- }
- else
- {
- addKeys.add(key);
- }
- }
- break;
-
- case DELETE:
- for (ASN1OctetString key : keys)
- {
- if (addKeys.contains(key))
- {
- addKeys.remove(key);
- }
- else
- {
- delKeys.add(key);
- }
- }
- break;
- }
- }
+ indexAttribute(oldAttributes, delKeys);
}
else
{
- // This is the non-optimized case that should be correct in all cases.
+ if(oldAttributes == null)
+ {
+ indexAttribute(newAttributes, addKeys);
+ }
+ else
+ {
+ newValues = new HashSet<AttributeValue>();
+ oldValues = new HashSet<AttributeValue>();
+ for(Attribute a : newAttributes)
+ {
+ newValues.addAll(a.getValues());
+ }
+ for(Attribute a : oldAttributes)
+ {
+ oldValues.addAll(a.getValues());
+ }
- Set<ASN1OctetString> oldSet = new HashSet<ASN1OctetString>();
- indexAttribute(beforeList, oldSet);
+ HashSet<AttributeValue> valuesToAdd =
+ new HashSet<AttributeValue>(newValues);
+ HashSet<AttributeValue> valuesToDel =
+ new HashSet<AttributeValue>(oldValues);
+ valuesToAdd.removeAll(oldValues);
+ valuesToDel.removeAll(newValues);
- Set<ASN1OctetString> newSet = new HashSet<ASN1OctetString>();
- indexAttribute(afterList, newSet);
-
- HashSet<ASN1OctetString> removeSet = new HashSet<ASN1OctetString>(oldSet);
- removeSet.removeAll(newSet);
- delKeys.addAll(removeSet);
-
- HashSet<ASN1OctetString> addSet = new HashSet<ASN1OctetString>(newSet);
- addSet.removeAll(oldSet);
- addKeys.addAll(addSet);
+ indexValues(valuesToDel, delKeys);
+ indexValues(valuesToAdd, addKeys);
+ }
}
}
diff --git a/opends/src/server/org/opends/server/backends/jeb/OrderingIndexer.java b/opends/src/server/org/opends/server/backends/jeb/OrderingIndexer.java
index 70d9b15..4c17058 100644
--- a/opends/src/server/org/opends/server/backends/jeb/OrderingIndexer.java
+++ b/opends/src/server/org/opends/server/backends/jeb/OrderingIndexer.java
@@ -180,72 +180,43 @@
Set<ASN1OctetString> delKeys)
throws DatabaseException
{
- List<Attribute> beforeList;
- beforeList = oldEntry.getAttribute(attributeType);
+ List<Attribute> newAttributes = newEntry.getAttribute(attributeType, true);
+ List<Attribute> oldAttributes = oldEntry.getAttribute(attributeType, true);
+ HashSet<AttributeValue> newValues;
+ HashSet<AttributeValue> oldValues;
- // Pick out the modifications that apply to this indexed attribute
-
- /**
- * FIXME unusual modifications can insert spurious index values
- * The following sequence of modifications will insert A into the
- * index, yet A is not a resulting value for the attribute.
- *
- * add: cn
- * cn: A
- * -
- * replace: cn
- * cn: B
- * -
- *
- */
-
- for (Modification mod : mods)
+ if(newAttributes == null)
{
- Attribute modAttr = mod.getAttribute();
- AttributeType modAttrType = modAttr.getAttributeType();
- if (modAttrType.equals(attributeType))
+ indexAttribute(oldAttributes, delKeys);
+ }
+ else
+ {
+ if(oldAttributes == null)
{
- switch (mod.getModificationType())
+ indexAttribute(newAttributes, addKeys);
+ }
+ else
+ {
+ newValues = new HashSet<AttributeValue>();
+ oldValues = new HashSet<AttributeValue>();
+ for(Attribute a : newAttributes)
{
- case REPLACE:
- case INCREMENT:
- if (beforeList != null)
- {
- for (Attribute attr : beforeList)
- {
- if (attr.hasOptions(modAttr.getOptions()))
- {
- indexValues(attr.getValues(), delKeys);
- }
- }
- }
- indexValues(modAttr.getValues(), addKeys);
- break;
-
- case ADD:
- indexValues(modAttr.getValues(), addKeys);
- break;
-
- case DELETE:
- if (!modAttr.hasValue())
- {
- if (beforeList != null)
- {
- for (Attribute attr : beforeList)
- {
- if (attr.hasOptions(modAttr.getOptions()))
- {
- indexValues(attr.getValues(), delKeys);
- }
- }
- }
- }
- else
- {
- indexValues(modAttr.getValues(), delKeys);
- }
- break;
+ newValues.addAll(a.getValues());
}
+ for(Attribute a : oldAttributes)
+ {
+ oldValues.addAll(a.getValues());
+ }
+
+ HashSet<AttributeValue> valuesToAdd =
+ new HashSet<AttributeValue>(newValues);
+ HashSet<AttributeValue> valuesToDel =
+ new HashSet<AttributeValue>(oldValues);
+ valuesToAdd.removeAll(oldValues);
+ valuesToDel.removeAll(newValues);
+
+ indexValues(valuesToDel, delKeys);
+ indexValues(valuesToAdd, addKeys);
}
}
}
diff --git a/opends/src/server/org/opends/server/backends/jeb/PresenceIndexer.java b/opends/src/server/org/opends/server/backends/jeb/PresenceIndexer.java
index 887746f..c1fa5a6 100644
--- a/opends/src/server/org/opends/server/backends/jeb/PresenceIndexer.java
+++ b/opends/src/server/org/opends/server/backends/jeb/PresenceIndexer.java
@@ -171,6 +171,23 @@
Set<ASN1OctetString> delKeys)
throws DatabaseException
{
- replaceEntry(txn, oldEntry, newEntry, addKeys, delKeys);
+ List<Attribute> newAttributes = newEntry.getAttribute(attributeType, true);
+ List<Attribute> oldAttributes = oldEntry.getAttribute(attributeType, true);
+ if(oldAttributes == null)
+ {
+ if(newAttributes != null)
+ {
+ addKeys.add(
+ new ASN1OctetString(AttributeIndex.presenceKey.getData()));
+ }
+ }
+ else
+ {
+ if(newAttributes == null)
+ {
+ delKeys.add(
+ new ASN1OctetString(AttributeIndex.presenceKey.getData()));
+ }
+ }
}
}
diff --git a/opends/src/server/org/opends/server/backends/jeb/SubstringIndexer.java b/opends/src/server/org/opends/server/backends/jeb/SubstringIndexer.java
index a9d04c9..9024da4 100644
--- a/opends/src/server/org/opends/server/backends/jeb/SubstringIndexer.java
+++ b/opends/src/server/org/opends/server/backends/jeb/SubstringIndexer.java
@@ -34,7 +34,6 @@
import java.util.Comparator;
import java.util.HashSet;
-import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
@@ -179,7 +178,37 @@
Set<ASN1OctetString> addKeys,
Set<ASN1OctetString> delKeys)
{
- replaceEntry(txn, oldEntry, newEntry, addKeys, delKeys);
+ List<Attribute> newAttributes = newEntry.getAttribute(attributeType, true);
+ List<Attribute> oldAttributes = oldEntry.getAttribute(attributeType, true);
+ HashSet<AttributeValue> newValues;
+ HashSet<AttributeValue> oldValues;
+
+ if(newAttributes == null)
+ {
+ indexAttribute(oldAttributes, delKeys);
+ }
+ else
+ {
+ if(oldAttributes == null)
+ {
+ indexAttribute(newAttributes, addKeys);
+ }
+ else
+ {
+ HashSet<ASN1OctetString> newKeys =
+ new HashSet<ASN1OctetString>();
+ HashSet<ASN1OctetString> oldKeys =
+ new HashSet<ASN1OctetString>();
+ indexAttribute(newAttributes, newKeys);
+ indexAttribute(oldAttributes, oldKeys);
+
+ addKeys.addAll(newKeys);
+ addKeys.removeAll(oldKeys);
+
+ delKeys.addAll(oldKeys);
+ delKeys.removeAll(newKeys);
+ }
+ }
}
@@ -187,30 +216,42 @@
/**
* Generate the set of substring index keys for an attribute.
* @param attrList The attribute for which substring keys are required.
- * @param addKeys The set into which the generated keys will be inserted.
+ * @param keys The set into which the generated keys will be inserted.
*/
private void indexAttribute(List<Attribute> attrList,
- Set<ASN1OctetString> addKeys)
+ Set<ASN1OctetString> keys)
{
if (attrList == null) return;
for (Attribute attr : attrList)
{
- LinkedHashSet<AttributeValue> values = attr.getValues();
- for (AttributeValue value : values)
- {
- try
- {
- byte[] normalizedBytes = value.getNormalizedValue().value();
+ indexValues(attr.getValues(), keys);
+ }
+ }
- substringKeys(normalizedBytes, addKeys);
- }
- catch (DirectoryException e)
+ /**
+ * Generate the set of index keys for a set of attribute values.
+ * @param values The set of attribute values to be indexed.
+ * @param keys The set into which the keys will be inserted.
+ */
+ private void indexValues(Set<AttributeValue> values,
+ Set<ASN1OctetString> keys)
+ {
+ if (values == null) return;
+
+ for (AttributeValue value : values)
+ {
+ try
+ {
+ byte[] normalizedBytes = value.getNormalizedValue().value();
+
+ substringKeys(normalizedBytes, keys);
+ }
+ catch (DirectoryException e)
+ {
+ if (debugEnabled())
{
- if (debugEnabled())
- {
- TRACER.debugCaught(DebugLogLevel.ERROR, e);
- }
+ TRACER.debugCaught(DebugLogLevel.ERROR, e);
}
}
}
diff --git a/opends/src/server/org/opends/server/backends/jeb/VLVIndex.java b/opends/src/server/org/opends/server/backends/jeb/VLVIndex.java
index 0f24189..00de153 100644
--- a/opends/src/server/org/opends/server/backends/jeb/VLVIndex.java
+++ b/opends/src/server/org/opends/server/backends/jeb/VLVIndex.java
@@ -383,14 +383,25 @@
SortKey[] sortKeys = sortOrder.getSortKeys();
for(SortKey sortKey : sortKeys)
{
+ AttributeType attributeType = sortKey.getAttributeType();
+ Iterable<AttributeType> subTypes =
+ DirectoryServer.getSchema().getSubTypes(attributeType);
for(Modification mod : mods)
{
- if(mod.getAttribute().getAttributeType().
- equals(sortKey.getAttributeType()))
+ AttributeType modAttrType = mod.getAttribute().getAttributeType();
+ if(modAttrType.equals(attributeType))
{
sortAttributeModified = true;
break;
}
+ for(AttributeType subType : subTypes)
+ {
+ if(modAttrType.equals(subType))
+ {
+ sortAttributeModified = true;
+ break;
+ }
+ }
}
if(sortAttributeModified)
{
diff --git a/opends/src/server/org/opends/server/types/Entry.java b/opends/src/server/org/opends/server/types/Entry.java
index 461143e..52f7b9c 100644
--- a/opends/src/server/org/opends/server/types/Entry.java
+++ b/opends/src/server/org/opends/server/types/Entry.java
@@ -608,25 +608,47 @@
}
-
/**
* Indicates whether this entry contains the specified attribute.
+ * Any subordinate attribute of the specified attribute will also
+ * be used in the determination.
*
- * @param attributeType The attribute type for which to make the
- * determination.
+ *
+ * @param attributeType The attribute type for which to
+ * make the determination.
*
* @return <CODE>true</CODE> if this entry contains the specified
* attribute, or <CODE>false</CODE> if not.
*/
public boolean hasAttribute(AttributeType attributeType)
{
+ return hasAttribute(attributeType, true);
+ }
+
+
+ /**
+ * Indicates whether this entry contains the specified attribute.
+ *
+ * @param attributeType The attribute type for which to
+ * make the determination.
+ * @param includeSubordinates Whether to include any subordinate
+ * attributes of the attribute type
+ * being retrieved.
+ *
+ * @return <CODE>true</CODE> if this entry contains the specified
+ * attribute, or <CODE>false</CODE> if not.
+ */
+ public boolean hasAttribute(AttributeType attributeType,
+ boolean includeSubordinates)
+ {
if (userAttributes.containsKey(attributeType) ||
operationalAttributes.containsKey(attributeType))
{
return true;
}
- if (attributeType.mayHaveSubordinateTypes())
+ if (includeSubordinates &&
+ attributeType.mayHaveSubordinateTypes())
{
for (AttributeType at : schema.getSubTypes(attributeType))
{
@@ -643,15 +665,16 @@
}
-
/**
* Indicates whether this entry contains the specified attribute
- * with all of the options in the provided set.
+ * with all of the options in the provided set. Any subordinate
+ * attribute of the specified attribute will also be used in
+ * the determination.
*
- * @param attributeType The attribute type for which to make
- * the determination.
- * @param attributeOptions The set of options to use in the
- * determination.
+ * @param attributeType The attribute type for which to
+ * make the determination.
+ * @param attributeOptions The set of options to use in the
+ * determination.
*
* @return <CODE>true</CODE> if this entry contains the specified
* attribute, or <CODE>false</CODE> if not.
@@ -659,8 +682,32 @@
public boolean hasAttribute(AttributeType attributeType,
Set<String> attributeOptions)
{
+ return hasAttribute(attributeType, true, attributeOptions);
+ }
+
+
+ /**
+ * Indicates whether this entry contains the specified attribute
+ * with all of the options in the provided set.
+ *
+ * @param attributeType The attribute type for which to
+ * make the determination.
+ * @param includeSubordinates Whether to include any subordinate
+ * attributes of the attribute type
+ * being retrieved.
+ * @param attributeOptions The set of options to use in the
+ * determination.
+ *
+ * @return <CODE>true</CODE> if this entry contains the specified
+ * attribute, or <CODE>false</CODE> if not.
+ */
+ public boolean hasAttribute(AttributeType attributeType,
+ boolean includeSubordinates,
+ Set<String> attributeOptions)
+ {
List<Attribute> attributes;
- if (attributeType.mayHaveSubordinateTypes())
+ if (includeSubordinates &&
+ attributeType.mayHaveSubordinateTypes())
{
attributes = new LinkedList<Attribute>();
List<Attribute> attrs = userAttributes.get(attributeType);
@@ -726,13 +773,12 @@
return false;
}
-
-
/**
* Retrieves the requested attribute element(s) for the specified
* attribute type. The list returned may include multiple elements
* if the same attribute exists in the entry multiple times with
- * different sets of options.
+ * different sets of options. It may also include any subordinate
+ * attributes of the attribute being retrieved.
*
* @param attributeType The attribute type to retrieve.
*
@@ -742,7 +788,30 @@
*/
public List<Attribute> getAttribute(AttributeType attributeType)
{
- if (attributeType.mayHaveSubordinateTypes())
+ return getAttribute(attributeType, true);
+ }
+
+
+ /**
+ * Retrieves the requested attribute element(s) for the specified
+ * attribute type. The list returned may include multiple elements
+ * if the same attribute exists in the entry multiple times with
+ * different sets of options.
+ *
+ * @param attributeType The attribute type to retrieve.
+ * @param includeSubordinates Whether to include any subordinate
+ * attributes of the attribute type
+ * being retrieved.
+ *
+ * @return The requested attribute element(s) for the specified
+ * attribute type, or <CODE>null</CODE> if the specified
+ * attribute type is not present in this entry.
+ */
+ public List<Attribute> getAttribute(AttributeType attributeType,
+ boolean includeSubordinates)
+ {
+ if (includeSubordinates &&
+ attributeType.mayHaveSubordinateTypes())
{
List<Attribute> attributes = new LinkedList<Attribute>();
@@ -821,7 +890,9 @@
* Retrieves the requested attribute element(s) for the attribute
* with the specified name or OID. The list returned may include
* multiple elements if the same attribute exists in the entry
- * multiple times with different sets of options.
+ * multiple times with different sets of options. It may also
+ * include any subordinate attributes of the attribute being
+ * retrieved.
* <BR><BR>
* Note that this method should only be used in cases in which the
* Directory Server schema has no reference of an attribute type
@@ -842,7 +913,7 @@
{
if (attr.hasNameOrOID(lowerName))
{
- return getAttribute(attr);
+ return getAttribute(attr, true);
}
}
@@ -850,7 +921,7 @@
{
if (attr.hasNameOrOID(lowerName))
{
- return getAttribute(attr);
+ return getAttribute(attr, true);
}
}
@@ -865,17 +936,16 @@
return null;
}
-
-
/**
* Retrieves the requested attribute element(s) for the specified
* attribute type. The list returned may include multiple elements
* if the same attribute exists in the entry multiple times with
- * different sets of options.
+ * different sets of options. It may also include any subordinate
+ * attributes of the attribute being retrieved.
*
- * @param attributeType The attribute type to retrieve.
- * @param options The set of attribute options to include in
- * matching elements.
+ * @param attributeType The attribute type to retrieve.
+ * @param options The set of attribute options to
+ * include in matching elements.
*
* @return The requested attribute element(s) for the specified
* attribute type, or <CODE>null</CODE> if the specified
@@ -885,8 +955,34 @@
public List<Attribute> getAttribute(AttributeType attributeType,
Set<String> options)
{
+ return getAttribute(attributeType, true, options);
+ }
+
+ /**
+ * Retrieves the requested attribute element(s) for the specified
+ * attribute type. The list returned may include multiple elements
+ * if the same attribute exists in the entry multiple times with
+ * different sets of options.
+ *
+ * @param attributeType The attribute type to retrieve.
+ * @param includeSubordinates Whether to include any subordinate
+ * attributes of the attribute type
+ * being retrieved.
+ * @param options The set of attribute options to
+ * include in matching elements.
+ *
+ * @return The requested attribute element(s) for the specified
+ * attribute type, or <CODE>null</CODE> if the specified
+ * attribute type is not present in this entry with the
+ * provided set of options.
+ */
+ public List<Attribute> getAttribute(AttributeType attributeType,
+ boolean includeSubordinates,
+ Set<String> options)
+ {
List<Attribute> attributes = new LinkedList<Attribute>();
- if (attributeType.mayHaveSubordinateTypes())
+ if (includeSubordinates &&
+ attributeType.mayHaveSubordinateTypes())
{
List<Attribute> attrs = userAttributes.get(attributeType);
if (attrs != null)
@@ -1053,7 +1149,7 @@
public final <T> T getAttributeValue(AttributeType attributeType,
AttributeValueDecoder<T> decoder) throws DirectoryException
{
- List<Attribute> attributes = getAttribute(attributeType);
+ List<Attribute> attributes = getAttribute(attributeType, true);
AttributeValueIterable values =
new AttributeValueIterable(attributes);
Iterator<AttributeValue> iterator = values.iterator();
@@ -1100,7 +1196,7 @@
Collection<T> collection)
throws DirectoryException
{
- List<Attribute> attributes = getAttribute(attributeType);
+ List<Attribute> attributes = getAttribute(attributeType, true);
AttributeValueIterable values =
new AttributeValueIterable(attributes);
@@ -1664,7 +1760,7 @@
attachment = null;
List<Attribute> attrList =
- getAttribute(attribute.getAttributeType());
+ getAttribute(attribute.getAttributeType(), false);
if (attrList == null)
{
// There are no instances of the specified attribute in this
@@ -1721,10 +1817,11 @@
/**
* Removes all instances of the specified attribute type from this
- * entry. If the provided attribute type is the objectclass type,
- * then all objectclass values will be removed (but must be replaced
- * for the entry to be valid). If the specified attribute type is
- * not present in this entry, then this method will have no effect.
+ * entry, including any instances with options. If the provided
+ * attribute type is the objectclass type, then all objectclass
+ * values will be removed (but must be replaced for the entry to
+ * be valid). If the specified attribute type is not present in
+ * this entry, then this method will have no effect.
*
* @param attributeType The attribute type for the attribute to
* remove from this entry.
@@ -1753,12 +1850,10 @@
/**
* Removes the attribute with the provided type and set of options
- * from this entry. If the provided set of options is
- * <CODE>null</CODE> or empty, then all occurrences of the specified
- * attribute will be removed. Otherwise, only the instance with the
- * exact set of options provided will be removed. This has no
- * effect if the specified attribute is not present in this entry
- * with the given set of options.
+ * from this entry. Only the instance with the exact set of
+ * options provided will be removed. This has no effect if the
+ * specified attribute is not present in this entry with the given
+ * set of options.
*
* @param attributeType The attribute type for the attribute to
* remove from this entry.
@@ -1774,44 +1869,37 @@
{
attachment = null;
- if ((options == null) || options.isEmpty())
+ List<Attribute> attrList = userAttributes.get(attributeType);
+ if (attrList == null)
{
- return removeAttribute(attributeType);
- }
- else
- {
- List<Attribute> attrList = userAttributes.get(attributeType);
+ attrList = operationalAttributes.get(attributeType);
if (attrList == null)
{
- attrList = operationalAttributes.get(attributeType);
- if (attrList == null)
- {
- return false;
- }
+ return false;
}
-
- boolean removed = false;
-
- Iterator<Attribute> iterator = attrList.iterator();
- while (iterator.hasNext())
- {
- Attribute a = iterator.next();
- if (a.optionsEqual(options))
- {
- iterator.remove();
- removed = true;
- break;
- }
- }
-
- if (attrList.isEmpty())
- {
- userAttributes.remove(attributeType);
- operationalAttributes.remove(attributeType);
- }
-
- return removed;
}
+
+ boolean removed = false;
+
+ Iterator<Attribute> iterator = attrList.iterator();
+ while (iterator.hasNext())
+ {
+ Attribute a = iterator.next();
+ if (a.optionsEqual(options))
+ {
+ iterator.remove();
+ removed = true;
+ break;
+ }
+ }
+
+ if (attrList.isEmpty())
+ {
+ userAttributes.remove(attributeType);
+ operationalAttributes.remove(attributeType);
+ }
+
+ return removed;
}
@@ -1906,7 +1994,7 @@
}
List<Attribute> attrList =
- getAttribute(attribute.getAttributeType());
+ getAttribute(attribute.getAttributeType(), false);
if (attrList == null)
{
return false;
@@ -1944,11 +2032,11 @@
LinkedHashSet<AttributeValue> valueSet = attribute.getValues();
if ((valueSet == null) || valueSet.isEmpty())
{
- return removeAttribute(attribute.getAttributeType());
+ return removeAttribute(attribute.getAttributeType(), null);
}
List<Attribute> attrList =
- getAttribute(attribute.getAttributeType());
+ getAttribute(attribute.getAttributeType(), false);
if (attrList == null)
{
return false;
@@ -1971,7 +2059,8 @@
if (existingValueSet.isEmpty())
{
- return removeAttribute(attribute.getAttributeType());
+ return removeAttribute(attribute.getAttributeType(),
+ null);
}
return true;
@@ -2050,7 +2139,7 @@
public boolean hasValue(AttributeType attributeType,
Set<String> options, AttributeValue value)
{
- List<Attribute> attrList = getAttribute(attributeType);
+ List<Attribute> attrList = getAttribute(attributeType, true);
if ((attrList == null) || attrList.isEmpty())
{
return false;
@@ -2196,7 +2285,7 @@
break;
case INCREMENT:
- List<Attribute> attrList = getAttribute(t);
+ List<Attribute> attrList = getAttribute(t, false);
if ((attrList == null) || attrList.isEmpty())
{
Message message =
diff --git a/opends/tests/unit-tests-testng/resource/config-changes.ldif b/opends/tests/unit-tests-testng/resource/config-changes.ldif
index 9ee7b7c..2ca81f4 100644
--- a/opends/tests/unit-tests-testng/resource/config-changes.ldif
+++ b/opends/tests/unit-tests-testng/resource/config-changes.ldif
@@ -1246,6 +1246,18 @@
objectClass: ds-cfg-branch
cn: Index
+dn: ds-cfg-attribute=name,cn=Index,ds-cfg-backend-id=indexRoot,cn=Backends,cn=config
+changetype: add
+objectClass: top
+objectClass: ds-cfg-local-db-index
+ds-cfg-attribute: name
+ds-cfg-index-type: presence
+ds-cfg-index-type: equality
+ds-cfg-index-type: substring
+ds-cfg-index-type: ordering
+ds-cfg-index-type: approximate
+ds-cfg-index-entry-limit: 4000
+
dn: ds-cfg-attribute=cn,cn=Index,ds-cfg-backend-id=indexRoot,cn=Backends,cn=config
changetype: add
objectClass: top
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestBackendImpl.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestBackendImpl.java
index 8595001..10f0180 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestBackendImpl.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestBackendImpl.java
@@ -129,6 +129,9 @@
"objectClass: organizationalPerson",
"objectClass: inetOrgPerson",
"givenName: Aaren",
+ "givenName;lang-fr: test2",
+ "givenName;lang-cn: test2",
+ "givenName;lang-es: test3",
"sn: Atp",
"cn: Aaren Atp",
"initials: APA",
@@ -1019,7 +1022,8 @@
Entry newEntry;
EntryID entryID;
AttributeType attribute;
- AttributeIndex index;
+ AttributeIndex titleIndex;
+ AttributeIndex nameIndex;
HashSet<ASN1OctetString> addKeys;
DatabaseEntry key;
PresenceIndexer presenceIndexer;
@@ -1036,12 +1040,46 @@
ArrayList<Modification> modifications = new ArrayList<Modification>();
modifications.add(new Modification(ModificationType.ADD, new
Attribute("title", "debugger")));
+
+ attribute = DirectoryServer.getAttributeType("title");
+ LinkedHashSet<AttributeValue> values = new LinkedHashSet<AttributeValue>();
+ values.add(new AttributeValue(attribute, "debugger2"));
+ LinkedHashSet<String> options = new LinkedHashSet<String>(1);
+ options.add("lang-en");
+ Attribute attr = new Attribute(attribute, "title", options, values);
+ modifications.add(new Modification(ModificationType.ADD, attr));
+
modifications.add(new Modification(ModificationType.DELETE, new
Attribute("cn", "Aaren Atp")));
modifications.add(new Modification(ModificationType.ADD, new
Attribute("cn", "Aaren Rigor")));
modifications.add(new Modification(ModificationType.ADD, new
Attribute("cn", "Aarenister Rigor")));
+
+ attribute = DirectoryServer.getAttributeType("givenname");
+ values = new LinkedHashSet<AttributeValue>();
+ values.add(new AttributeValue(attribute, "test"));
+ options = new LinkedHashSet<String>(1);
+ options.add("lang-de");
+ attr = new Attribute(attribute, "givenName", options, values);
+ modifications.add(new Modification(ModificationType.ADD, attr));
+
+ attribute = DirectoryServer.getAttributeType("givenname");
+ values = new LinkedHashSet<AttributeValue>();
+ values.add(new AttributeValue(attribute, "test2"));
+ options = new LinkedHashSet<String>(1);
+ options.add("lang-cn");
+ attr = new Attribute(attribute, "givenName", options, values);
+ modifications.add(new Modification(ModificationType.DELETE, attr));
+
+ attribute = DirectoryServer.getAttributeType("givenname");
+ values = new LinkedHashSet<AttributeValue>();
+ values.add(new AttributeValue(attribute, "newtest3"));
+ options = new LinkedHashSet<String>(1);
+ options.add("lang-es");
+ attr = new Attribute(attribute, "givenName", options, values);
+ modifications.add(new Modification(ModificationType.REPLACE, attr));
+
modifications.add(new Modification(ModificationType.REPLACE, new
Attribute("employeenumber", "222")));
@@ -1053,19 +1091,31 @@
assertNotNull(entryID);
- attribute = newEntry.getAttribute("title").get(0).getAttributeType();
- index = ec.getAttributeIndex(attribute);
+ attribute = DirectoryServer.getAttributeType("title");
+ titleIndex = ec.getAttributeIndex(attribute);
+ attribute = DirectoryServer.getAttributeType("name");
+ nameIndex = ec.getAttributeIndex(attribute);
- //This current entry in the DB shouldn't be in the presence index.
+ //This current entry in the DB shouldn't be in the presence titleIndex.
addKeys = new HashSet<ASN1OctetString>();
addKeys.add(new ASN1OctetString(AttributeIndex.presenceKey.getData()));
key = new DatabaseEntry();
for (ASN1OctetString keyBytes : addKeys) {
key.setData(keyBytes.value());
}
- assertEquals(index.presenceIndex.containsID(null, key, entryID),
+ assertEquals(titleIndex.presenceIndex.containsID(null, key, entryID),
ConditionResult.FALSE);
+ //This current entry should be in the presence nameIndex.
+ addKeys = new HashSet<ASN1OctetString>();
+ addKeys.add(new ASN1OctetString(AttributeIndex.presenceKey.getData()));
+ key = new DatabaseEntry();
+ for (ASN1OctetString keyBytes : addKeys) {
+ key.setData(keyBytes.value());
+ }
+ assertEquals(nameIndex.presenceIndex.containsID(null, key, entryID),
+ ConditionResult.TRUE);
+
ArrayList<Control> noControls = new ArrayList<Control>(0);
InternalClientConnection conn =
InternalClientConnection.getRootConnection();
@@ -1098,55 +1148,123 @@
entry.getAttribute("cn").get(0).getAttributeType(),
"Aaren Atp")));
+ options = new LinkedHashSet<String>();
+ options.add("lang-de");
+ assertTrue(entry.getAttribute("givenname", options).get(0).getValues().contains(
+ new AttributeValue(
+ entry.getAttribute("givenname", options).get(0).getAttributeType(),
+ "test")));
+ options = new LinkedHashSet<String>();
+ options.add("lang-cn");
+ assertNull
+ (entry.getAttribute("givenname", options));
+ options = new LinkedHashSet<String>();
+ options.add("lang-es");
+ assertTrue(entry.getAttribute("givenname", options).get(0).getValues().contains(
+ new AttributeValue(
+ entry.getAttribute("givenname", options).get(0).getAttributeType(),
+ "newtest3")));
+ options = new LinkedHashSet<String>();
+ options.add("lang-fr");
+ assertTrue(entry.getAttribute("givenname", options).get(0).getValues().contains(
+ new AttributeValue(
+ entry.getAttribute("givenname", options).get(0).getAttributeType(),
+ "test2")));
+
assertTrue(entry.getAttribute("employeenumber").contains(new
Attribute("employeenumber", "222")));
assertFalse(entry.getAttribute("employeenumber").contains(new
Attribute("employeenumber", "1")));
addKeys = new HashSet<ASN1OctetString>();
- presenceIndexer = new PresenceIndexer(index.getAttributeType());
+ presenceIndexer = new PresenceIndexer(titleIndex.getAttributeType());
presenceIndexer.indexEntry(null, entry, addKeys);
key = new DatabaseEntry();
for (ASN1OctetString keyBytes : addKeys) {
key.setData(keyBytes.value());
- }
- assertEquals(index.presenceIndex.containsID(null, key, entryID),
+ assertEquals(titleIndex.presenceIndex.containsID(null, key, entryID),
ConditionResult.TRUE);
+ }
addKeys = new HashSet<ASN1OctetString>();
- orderingIndexer = new OrderingIndexer(index.getAttributeType());
+ presenceIndexer = new PresenceIndexer(nameIndex.getAttributeType());
+ presenceIndexer.indexEntry(null, entry, addKeys);
+
+ key = new DatabaseEntry();
+ for (ASN1OctetString keyBytes : addKeys) {
+ key.setData(keyBytes.value());
+ assertEquals(nameIndex.presenceIndex.containsID(null, key, entryID),
+ ConditionResult.TRUE);
+ }
+
+ addKeys = new HashSet<ASN1OctetString>();
+ orderingIndexer = new OrderingIndexer(titleIndex.getAttributeType());
orderingIndexer.indexEntry(null, entry, addKeys);
key = new DatabaseEntry();
for (ASN1OctetString keyBytes : addKeys) {
key.setData(keyBytes.value());
- }
- assertEquals(index.orderingIndex.containsID(null, key, entryID),
+ assertEquals(titleIndex.orderingIndex.containsID(null, key, entryID),
ConditionResult.TRUE);
+ }
addKeys = new HashSet<ASN1OctetString>();
- equalityIndexer = new EqualityIndexer(index.getAttributeType());
+ orderingIndexer = new OrderingIndexer(nameIndex.getAttributeType());
+ orderingIndexer.indexEntry(null, entry, addKeys);
+
+ key = new DatabaseEntry();
+ for (ASN1OctetString keyBytes : addKeys) {
+ key.setData(keyBytes.value());
+ assertEquals(nameIndex.orderingIndex.containsID(null, key, entryID),
+ ConditionResult.TRUE);
+ }
+
+ addKeys = new HashSet<ASN1OctetString>();
+ equalityIndexer = new EqualityIndexer(titleIndex.getAttributeType());
equalityIndexer.indexEntry(null, entry, addKeys);
key = new DatabaseEntry();
for (ASN1OctetString keyBytes : addKeys) {
key.setData(keyBytes.value());
- }
- assertEquals(index.equalityIndex.containsID(null, key, entryID),
+ assertEquals(titleIndex.equalityIndex.containsID(null, key, entryID),
ConditionResult.TRUE);
+ }
addKeys = new HashSet<ASN1OctetString>();
- substringIndexer = new SubstringIndexer(index.getAttributeType(),
- index.getConfiguration().getSubstringLength());
+ equalityIndexer = new EqualityIndexer(nameIndex.getAttributeType());
+ equalityIndexer.indexEntry(null, entry, addKeys);
+
+ key = new DatabaseEntry();
+ for (ASN1OctetString keyBytes : addKeys) {
+ key.setData(keyBytes.value());
+ assertEquals(nameIndex.equalityIndex.containsID(null, key, entryID),
+ ConditionResult.TRUE);
+ }
+
+ addKeys = new HashSet<ASN1OctetString>();
+ substringIndexer = new SubstringIndexer(titleIndex.getAttributeType(),
+ titleIndex.getConfiguration().getSubstringLength());
substringIndexer.indexEntry(null, entry, addKeys);
key = new DatabaseEntry();
for (ASN1OctetString keyBytes : addKeys) {
key.setData(keyBytes.value());
- }
- assertEquals(index.substringIndex.containsID(null, key, entryID),
+ assertEquals(titleIndex.substringIndex.containsID(null, key, entryID),
ConditionResult.TRUE);
+ }
+
+ addKeys = new HashSet<ASN1OctetString>();
+ substringIndexer = new SubstringIndexer(nameIndex.getAttributeType(),
+ nameIndex.getConfiguration().getSubstringLength());
+ substringIndexer.indexEntry(null, entry, addKeys);
+
+ key = new DatabaseEntry();
+ for (ASN1OctetString keyBytes : addKeys) {
+ key.setData(keyBytes.value());
+ assertEquals(nameIndex.substringIndex.containsID(null, key, entryID),
+ ConditionResult.TRUE);
+ }
}
finally
{
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/types/EntrySchemaCheckingTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/types/EntrySchemaCheckingTestCase.java
index dbb81a2..3f07c6f 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/types/EntrySchemaCheckingTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/types/EntrySchemaCheckingTestCase.java
@@ -1430,5 +1430,35 @@
invalidReason = new MessageBuilder();
failOnlyForStrictEvaluation(e);
}
+
+ /**
+ * Tests schema checking for an entry that includes an attribute not
+ * defined in any objectClasses but the subtypes of the attribute are.
+ *
+ * @throws Exception If an unexpected problem occurs.
+ */
+ @Test()
+ public void testInvalidSuperiorAttribute()
+ throws Exception
+ {
+ // The LDIF reader won't let us do this directly, so we have to hack around
+ // it.
+ Entry e = TestCaseUtils.makeEntry(
+ "dn: uid=test.user,o=test",
+ "objectClass: top",
+ "objectClass: person",
+ "objectClass: organizationalPerson",
+ "objectClass: inetOrgPerson",
+ "objectClass: account",
+ "uid: test.user",
+ "givenName: Test",
+ "sn: User",
+ "cn: Test User");
+
+ e.addAttribute(new Attribute("name", "foo"),
+ new LinkedList<AttributeValue>());
+
+ assertFalse(e.conformsToSchema(null, false, true, true, new MessageBuilder()));
+ }
}
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestEntry.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestEntry.java
index ccb0e3e..d3e4465 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestEntry.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestEntry.java
@@ -343,6 +343,7 @@
assertTrue(e.hasAttribute(ocType));
assertTrue(e.hasAttribute(cnType));
assertTrue(e.hasAttribute(nameType));
+ assertFalse(e.hasAttribute(nameType, false));
assertFalse(e.hasAttribute(uidType));
assertTrue(e.hasAttribute(mnType));
@@ -350,6 +351,7 @@
assertTrue(e.hasAttribute(ocType, options));
assertTrue(e.hasAttribute(cnType, options));
assertTrue(e.hasAttribute(nameType, options));
+ assertFalse(e.hasAttribute(nameType, false, options));
assertFalse(e.hasAttribute(uidType, options));
assertTrue(e.hasAttribute(mnType, options));
@@ -357,6 +359,7 @@
assertTrue(e.hasAttribute(ocType, options));
assertTrue(e.hasAttribute(cnType, options));
assertTrue(e.hasAttribute(nameType, options));
+ assertFalse(e.hasAttribute(nameType, false, options));
assertFalse(e.hasAttribute(uidType, options));
assertTrue(e.hasAttribute(mnType, options));
@@ -364,6 +367,7 @@
assertFalse(e.hasAttribute(ocType, options));
assertTrue(e.hasAttribute(cnType, options));
assertTrue(e.hasAttribute(nameType, options));
+ assertFalse(e.hasAttribute(nameType, false, options));
assertFalse(e.hasAttribute(uidType, options));
assertFalse(e.hasAttribute(mnType, options));
@@ -371,6 +375,7 @@
assertFalse(e.hasAttribute(ocType, options));
assertFalse(e.hasAttribute(cnType, options));
assertFalse(e.hasAttribute(nameType, options));
+ assertFalse(e.hasAttribute(nameType, false, options));
assertFalse(e.hasAttribute(uidType, options));
assertFalse(e.hasAttribute(mnType, options));
@@ -379,6 +384,7 @@
assertFalse(e.hasAttribute(ocType, options));
assertFalse(e.hasAttribute(cnType, options));
assertFalse(e.hasAttribute(nameType, options));
+ assertFalse(e.hasAttribute(nameType, false, options));
assertFalse(e.hasAttribute(uidType, options));
assertFalse(e.hasAttribute(mnType, options));
}
@@ -526,6 +532,9 @@
assertNotNull(attrs);
assertEquals(attrs.size(), 6);
+ attrs = e.getAttribute(nameType, false);
+ assertNull(attrs);
+
attrs = e.getAttribute(uidType);
assertNull(attrs);
@@ -563,6 +572,9 @@
assertNotNull(attrs);
assertEquals(attrs.size(), 6);
+ attrs = e.getAttribute(nameType, false, options);
+ assertNull(attrs);
+
attrs = e.getAttribute(uidType, options);
assertNull(attrs);
@@ -600,6 +612,9 @@
assertNotNull(attrs);
assertEquals(attrs.size(), 6);
+ attrs = e.getAttribute(nameType, false, options);
+ assertNull(attrs);
+
attrs = e.getAttribute(uidType, options);
assertNull(attrs);
@@ -636,6 +651,9 @@
assertNotNull(attrs);
assertEquals(attrs.size(), 3);
+ attrs = e.getAttribute(nameType, false, options);
+ assertNull(attrs);
+
attrs = e.getAttribute(uidType, options);
assertNull(attrs);
--
Gitblit v1.10.0