OPENDJ-1368 (CR-3232) Remove AttributeValue
Adressed comments from post commit review for r10554.
Code review: Matthew Swift
JebFormat.java:
In entryIDFromDatabase(), extracted toLong() for reuse outside of this class.
In entryIDUndefinedSizeFromDatabase(), called entryIDFromDatabase().
VlVIndex.java:
Extracted methods getSortValuesSet(), getSearchKeyRange(), logSearchKeyResult(), put(), moveToNextSortValues() to factorize code.
In evaluate(), regrouped guard clauses.
In getSortValues(), regrouped if statements.
In decodeKey(), called JebFormat.toLong().
VlVKeyComparator.java:
In compare(), called JebFormat.toLong().
In compare(), removed AttributeType[] parameter, no longer needed.
SortValuesSet.java:
In binarySearch(), removed AttributeType[] parameter, no longer needed (consequence of the change to VlVKeyComparator.compare()).
TestVerifyJob.java:
Consequence of removing AttributeType[] parameter from a few methods.
VirtualAttributeProvider.java:
Added matchesEqualityAssertion().
Fixed javadocs to speak about assertion values.
AbstractAttribute.java:
Pulled hashCode() implementation here from VirtualAttribute.
Attribute.java, CollectiveVirtualAttribute.java:
Added matchesEqualityAssertion().
Fixed javadocs + parameter names to speak about assertion values.
AttributeBuilder.java:
Used SmallMap instead of LinkedHashMap.
Added matchesEqualityAssertion().
Fixed javadocs + parameter names to speak about assertion values.
SmallMap.java, SmallMapTest.java: ADDED
VirtualAttribute.java:
Added matchesEqualityAssertion().
Fixed javadocs + parameter names to speak about assertion values.
Pulled up hashCode() implementation.
SearchFilter.java:
In processEquality(), changed implementation and called Attribute.matchesEqualityAssertion().
AttributeValueIterable.java: REMOVED
ServerManagementContext.java, TestEntry.java:
Consequence of removing AttributeValueIterable.
AttributeIndex.java:
Used normalizeAssertionValue() instead of normalizeAttributeValue() where appropriate.
ModifyEntryTask.java, UserDN.java:
Fixed small typo.
SearchFilterTests.java:
Code cleanup.
1 files deleted
2 files added
18 files modified
| | |
| | | } |
| | | |
| | | /** |
| | | * Creates an ByteString for an attribute and a value (the one we got |
| | | * using JNDI). |
| | | * Creates a ByteString for an attribute and a value (the one we got using JNDI). |
| | | * @param value the value found using JNDI. |
| | | * @return an ByteString object. |
| | | * @return a ByteString object. |
| | | */ |
| | | private static ByteString createAttributeValue(Object value) |
| | | { |
| | |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Portions Copyright 2014 ForgeRock AS |
| | | */ |
| | | |
| | | package org.opends.server.admin.server; |
| | | |
| | | |
| | | |
| | | import static org.opends.messages.AdminMessages.*; |
| | | import static org.opends.server.admin.PropertyException.*; |
| | | import static org.opends.server.util.StaticUtils.*; |
| | |
| | | import org.opends.server.config.ConfigEntry; |
| | | import org.opends.server.core.DirectoryServer; |
| | | import org.opends.server.types.Attribute; |
| | | import org.opends.server.types.AttributeValueIterable; |
| | | import org.opends.server.types.AttributeType; |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | | import org.opends.server.types.DN; |
| | |
| | | List<Attribute> attributes = configEntry.getEntry().getAttribute(type, true); |
| | | |
| | | List<ByteString> results = new LinkedList<ByteString>(); |
| | | for (ByteString v : new AttributeValueIterable(attributes)) |
| | | if (attributes != null) |
| | | { |
| | | results.add(v); |
| | | for (Attribute a : attributes) |
| | | { |
| | | for (ByteString v : a) |
| | | { |
| | | results.add(v); |
| | | } |
| | | } |
| | | } |
| | | return results; |
| | | } |
| | |
| | | return getValues(entry, rule).contains(value); |
| | | } |
| | | |
| | | /** |
| | | * Indicates whether this virtual attribute provider matches the assertion |
| | | * value. |
| | | * |
| | | * @param entry |
| | | * The entry for which to make the determination. |
| | | * @param rule |
| | | * The virtual attribute rule which defines the constraints for the |
| | | * virtual attribute. |
| | | * @param assertionValue |
| | | * The assertion value for which to make the determination. |
| | | * @return {@code true} if this virtual attribute provider matches the |
| | | * specified assertion value for the provided entry, or {@code false} |
| | | * if not. |
| | | */ |
| | | public ConditionResult matchesEqualityAssertion(Entry entry, |
| | | VirtualAttributeRule rule, ByteString assertionValue) |
| | | { |
| | | return getValues(entry, rule).matchesEqualityAssertion(assertionValue); |
| | | } |
| | | |
| | | |
| | | /** |
| | |
| | | * The virtual attribute rule which defines the constraints for the |
| | | * virtual attribute. |
| | | * @param assertionValue |
| | | * The value for which to make the determination. |
| | | * The assertion value for which to make the determination. |
| | | * @return {@code UNDEFINED} if the associated attribute type does not have an |
| | | * ordering matching rule, {@code TRUE} if at least one of the |
| | | * generated values will be greater than or equal to the specified |
| | | * value, or {@code FALSE} if none of the generated values will be |
| | | * greater than or equal to the specified value. |
| | | * assertion value, or {@code FALSE} if none of the generated values |
| | | * will be greater than or equal to the specified value. |
| | | */ |
| | | public ConditionResult greaterThanOrEqualTo(Entry entry, |
| | | VirtualAttributeRule rule, |
| | |
| | | * The virtual attribute rule which defines the constraints for the |
| | | * virtual attribute. |
| | | * @param assertionValue |
| | | * The value for which to make the determination. |
| | | * The assertion value for which to make the determination. |
| | | * @return {@code UNDEFINED} if the associated attribute type does not have an |
| | | * ordering matching rule, {@code TRUE} if at least one of the |
| | | * generated values will be less than or equal to the specified value, |
| | | * or {@code FALSE} if none of the generated values will be greater |
| | | * than or equal to the specified value. |
| | | * generated values will be less than or equal to the specified |
| | | * assertion value, or {@code FALSE} if none of the generated values |
| | | * will be greater than or equal to the specified value. |
| | | */ |
| | | public ConditionResult lessThanOrEqualTo(Entry entry, |
| | | VirtualAttributeRule rule, |
| | |
| | | * @param entry The entry for which to make the determination. |
| | | * @param rule The virtual attribute rule which defines the |
| | | * constraints for the virtual attribute. |
| | | * @param assertionValue The value for which to make the determination. |
| | | * @param assertionValue |
| | | * The assertion value for which to make the determination. |
| | | * |
| | | * @return {@code UNDEFINED} if the associated attribute type does |
| | | * not have an approximate matching rule, {@code TRUE} if at |
| | | * least one of the generated values will be approximately |
| | | * equal to the specified value, or {@code FALSE} if none |
| | | * of the generated values will be approximately equal to |
| | | * the specified value. |
| | | * the specified assertion value. |
| | | */ |
| | | public ConditionResult approximatelyEqualTo(Entry entry, |
| | | VirtualAttributeRule rule, |
| | |
| | | /* |
| | | * TODO Evaluate making this method more efficient. |
| | | * |
| | | * The evalDNEntryAttr method isn't as efficient as it could be. It would |
| | | * probably be faster to to convert the clientDN to an ByteString and |
| | | * see if the entry has that value than to decode each value as a DN and |
| | | * see if it matches the clientDN. |
| | | * The evalDNEntryAttr method isn't as efficient as it could be. |
| | | * It would probably be faster to to convert the clientDN to a ByteString |
| | | * and see if the entry has that value than to decode each value as a DN |
| | | * and see if it matches the clientDN. |
| | | */ |
| | | /** |
| | | * This method searches an entry for an attribute value that is |
| | |
| | | |
| | | import org.forgerock.i18n.LocalizableMessage; |
| | | import org.forgerock.i18n.slf4j.LocalizedLogger; |
| | | import org.forgerock.opendj.config.server.ConfigException; |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | | import org.forgerock.opendj.ldap.DecodeException; |
| | | import org.forgerock.opendj.ldap.ResultCode; |
| | |
| | | import org.opends.server.admin.std.meta.LocalDBIndexCfgDefn; |
| | | import org.opends.server.admin.std.server.LocalDBIndexCfg; |
| | | import org.opends.server.api.*; |
| | | import org.forgerock.opendj.config.server.ConfigException; |
| | | import org.opends.server.core.DirectoryServer; |
| | | import org.opends.server.monitors.DatabaseEnvironmentMonitor; |
| | | import org.opends.server.types.*; |
| | |
| | | try |
| | | { |
| | | // Use the ordering matching rule to normalize the value. |
| | | MatchingRule orderingRule = |
| | | filter.getAttributeType().getOrderingMatchingRule(); |
| | | // FIXME JNR this looks wrong, it should use normalizeAssertionValue() |
| | | byte[] normalizedValue = orderingRule.normalizeAttributeValue( |
| | | MatchingRule orderingRule = filter.getAttributeType().getOrderingMatchingRule(); |
| | | byte[] normalizedValue = orderingRule.normalizeAssertionValue( |
| | | filter.getAssertionValue()).toByteArray(); |
| | | |
| | | // Set the lower and upper bounds for a range search. |
| | |
| | | * equal to the lower bound value, and less than or equal to the |
| | | * upper bound value. |
| | | * |
| | | * @param lowerValue The lower bound value |
| | | * @param upperValue The upper bound value |
| | | * @param lowerValue The lower bound assertion value |
| | | * @param upperValue The upper bound assertion value |
| | | * @return The candidate entry IDs. |
| | | */ |
| | | public EntryIDSet evaluateBoundedRange(ByteString lowerValue, ByteString upperValue) |
| | |
| | | |
| | | try |
| | | { |
| | | // Use the ordering matching rule to normalize the values. |
| | | MatchingRule orderingRule = |
| | | getAttributeType().getOrderingMatchingRule(); |
| | | |
| | | // Set the lower and upper bounds for a range search. |
| | | byte[] lower = orderingRule.normalizeAttributeValue(lowerValue).toByteArray(); |
| | | byte[] upper = orderingRule.normalizeAttributeValue(upperValue).toByteArray(); |
| | | MatchingRule orderingRule = getAttributeType().getOrderingMatchingRule(); |
| | | byte[] lower = orderingRule.normalizeAssertionValue(lowerValue).toByteArray(); |
| | | byte[] upper = orderingRule.normalizeAssertionValue(upperValue).toByteArray(); |
| | | |
| | | // Read the range: lower <= keys <= upper. |
| | | return orderingIndex.readRange(lower, upper, true, true); |
| | |
| | | MatchingRule approximateMatchingRule = |
| | | approximateFilter.getAttributeType().getApproximateMatchingRule(); |
| | | // Make a key from the normalized assertion value. |
| | | // FIXME JNR this looks wrong, it should use normalizeAssertionValue() |
| | | byte[] keyBytes = approximateMatchingRule.normalizeAttributeValue( |
| | | byte[] keyBytes = approximateMatchingRule.normalizeAssertionValue( |
| | | approximateFilter.getAssertionValue()).toByteArray(); |
| | | DatabaseEntry key = new DatabaseEntry(keyBytes); |
| | | |
| | |
| | | */ |
| | | public static long entryIDFromDatabase(byte[] bytes) |
| | | { |
| | | return toLong(bytes, 0, 8); |
| | | } |
| | | |
| | | /** |
| | | * Decode a long from a byte array, starting at start index and ending at end |
| | | * index. |
| | | * |
| | | * @param bytes |
| | | * The bytes value of the long. |
| | | * @param start |
| | | * the array index where to start computing the long |
| | | * @param end |
| | | * the array index exclusive where to end computing the long |
| | | * @return the long representation of the read bytes. |
| | | * @throws ArrayIndexOutOfBoundsException |
| | | * if the bytes array length is less than end. |
| | | */ |
| | | public static long toLong(byte[] bytes, int start, int end) |
| | | throws ArrayIndexOutOfBoundsException |
| | | { |
| | | long v = 0; |
| | | for (int i = 0; i < 8; i++) |
| | | for (int i = start; i < end; i++) |
| | | { |
| | | v <<= 8; |
| | | v |= (bytes[i] & 0xFF); |
| | |
| | | |
| | | if(bytes.length == 8) |
| | | { |
| | | long v = 0; |
| | | v |= (bytes[0] & 0x7F); |
| | | for (int i = 1; i < 8; i++) |
| | | { |
| | | v <<= 8; |
| | | v |= (bytes[i] & 0xFF); |
| | | } |
| | | return v; |
| | | return entryIDFromDatabase(bytes); |
| | | } |
| | | return Long.MAX_VALUE; |
| | | } |
| | |
| | | return true; |
| | | } |
| | | if (vlvIndex.comparator.compare( |
| | | this, entryIDs.length - 1, entryID, values, types) < 0) |
| | | this, entryIDs.length - 1, entryID, values) < 0) |
| | | { |
| | | long[] updatedEntryIDs = new long[entryIDs.length + 1]; |
| | | System.arraycopy(entryIDs, 0, updatedEntryIDs, 0, entryIDs.length); |
| | |
| | | } |
| | | else |
| | | { |
| | | int pos = binarySearch(entryID, values, types); |
| | | int pos = binarySearch(entryID, values); |
| | | if(pos >= 0) |
| | | { |
| | | if(entryIDs[pos] == entryID) |
| | |
| | | * |
| | | * @param entryID The entry ID to remove. |
| | | * @param values The values to remove. |
| | | * @param types The types of the values to remove. |
| | | * @return True if the information was successfully removed or False |
| | | * otherwise. |
| | | * @throws DirectoryException If a Directory Server error occurs. |
| | | * @throws DatabaseException If an error occurs in the JE database. |
| | | */ |
| | | public boolean remove(long entryID, ByteString[] values, AttributeType[] types) |
| | | public boolean remove(long entryID, ByteString[] values) |
| | | throws DatabaseException, DirectoryException |
| | | { |
| | | if(entryIDs == null || entryIDs.length == 0) |
| | |
| | | updateValuesBytesOffsets(); |
| | | } |
| | | |
| | | int pos = binarySearch(entryID, values, types); |
| | | int pos = binarySearch(entryID, values); |
| | | if(pos < 0) |
| | | { |
| | | // Not found. |
| | |
| | | * |
| | | * @param entryID The entry ID to match or -1 if not matching on entry ID. |
| | | * @param values The values to match. |
| | | * @param types The types of the values to match. |
| | | * @return Index of the entry matching the values and optionally the entry ID |
| | | * if it is found or a negative index if its not found. |
| | | * @throws DirectoryException If a Directory Server error occurs. |
| | | * @throws DatabaseException If an error occurs in the JE database. |
| | | */ |
| | | int binarySearch(long entryID, ByteString[] values, AttributeType[] types) |
| | | int binarySearch(long entryID, ByteString... values) |
| | | throws DatabaseException, DirectoryException |
| | | { |
| | | if(entryIDs == null || entryIDs.length == 0) |
| | |
| | | for(int j = entryIDs.length - 1; i <= j;) |
| | | { |
| | | int k = i + j >> 1; |
| | | int l = vlvIndex.comparator.compare(this, k, entryID, values, types); |
| | | int l = vlvIndex.comparator.compare(this, k, entryID, values); |
| | | if (l < 0) |
| | | { |
| | | i = k + 1; |
| | |
| | | |
| | | try |
| | | { |
| | | this.filter = |
| | | SearchFilter.createFilterFromString(config.getFilter()); |
| | | this.filter = SearchFilter.createFilterFromString(config.getFilter()); |
| | | } |
| | | catch(Exception e) |
| | | { |
| | |
| | | |
| | | String[] sortAttrs = config.getSortOrder().split(" "); |
| | | SortKey[] sortKeys = new SortKey[sortAttrs.length]; |
| | | MatchingRule[] orderingRules = |
| | | new MatchingRule[sortAttrs.length]; |
| | | MatchingRule[] orderingRules = new MatchingRule[sortAttrs.length]; |
| | | boolean[] ascending = new boolean[sortAttrs.length]; |
| | | for(int i = 0; i < sortAttrs.length; i++) |
| | | { |
| | |
| | | ByteString[] values, AttributeType[] types) throws DatabaseException, |
| | | DirectoryException |
| | | { |
| | | SortValuesSet sortValuesSet = null; |
| | | DatabaseEntry key = new DatabaseEntry(); |
| | | OperationStatus status; |
| | | LockMode lockMode = LockMode.DEFAULT; |
| | | DatabaseEntry data = new DatabaseEntry(); |
| | | key.setData(encodeKey(entryID, values, types)); |
| | | return getSortValuesSet(txn, key, data, LockMode.DEFAULT); |
| | | } |
| | | |
| | | Cursor cursor = openCursor(txn, CursorConfig.READ_COMMITTED); |
| | | |
| | | try |
| | | private SortValuesSet getSortValuesSet(Transaction txn, DatabaseEntry key, |
| | | DatabaseEntry data, LockMode lockMode) |
| | | { |
| | | OperationStatus status = getSearchKeyRange(txn, key, data, lockMode); |
| | | if (status != OperationStatus.SUCCESS) |
| | | { |
| | | key.setData(encodeKey(entryID, values, types)); |
| | | status = cursor.getSearchKeyRange(key, data,lockMode); |
| | | |
| | | if(status != OperationStatus.SUCCESS) |
| | | // There are no records in the database |
| | | if (logger.isTraceEnabled()) |
| | | { |
| | | // There are no records in the database |
| | | if(logger.isTraceEnabled()) |
| | | { |
| | | logger.trace("No sort values set exist in VLV vlvIndex %s. " + |
| | | "Creating unbound set.", config.getName()); |
| | | } |
| | | sortValuesSet = new SortValuesSet(this); |
| | | logger.trace("No sort values set exist in VLV vlvIndex %s. " |
| | | + "Creating unbound set.", config.getName()); |
| | | } |
| | | else |
| | | { |
| | | if(logger.isTraceEnabled()) |
| | | { |
| | | StringBuilder searchKeyHex = new StringBuilder(); |
| | | StaticUtils.byteArrayToHexPlusAscii(searchKeyHex, key.getData(), 4); |
| | | StringBuilder foundKeyHex = new StringBuilder(); |
| | | StaticUtils.byteArrayToHexPlusAscii(foundKeyHex, key.getData(), 4); |
| | | logger.trace("Retrieved a sort values set in VLV vlvIndex " + |
| | | "%s\nSearch Key:%s\nFound Key:%s\n", |
| | | config.getName(), |
| | | searchKeyHex, |
| | | foundKeyHex); |
| | | } |
| | | sortValuesSet = new SortValuesSet(key.getData(), data.getData(), |
| | | this); |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | cursor.close(); |
| | | // this could not be found, so clean the key for later reuse |
| | | key.setData(new byte[0]); |
| | | return new SortValuesSet(this); |
| | | } |
| | | |
| | | return sortValuesSet; |
| | | if (logger.isTraceEnabled()) |
| | | { |
| | | logSearchKeyResult(key); |
| | | } |
| | | return new SortValuesSet(key.getData(), data.getData(), this); |
| | | } |
| | | |
| | | private void logSearchKeyResult(DatabaseEntry key) |
| | | { |
| | | StringBuilder searchKeyHex = new StringBuilder(); |
| | | StaticUtils.byteArrayToHexPlusAscii(searchKeyHex, key.getData(), 4); |
| | | StringBuilder foundKeyHex = new StringBuilder(); |
| | | StaticUtils.byteArrayToHexPlusAscii(foundKeyHex, key.getData(), 4); |
| | | logger.trace("Retrieved a sort values set in VLV vlvIndex %s\n" + |
| | | "Search Key:%s\nFound Key:%s\n", |
| | | config.getName(), searchKeyHex, foundKeyHex); |
| | | } |
| | | |
| | | /** |
| | |
| | | DatabaseException, DirectoryException |
| | | { |
| | | SortValuesSet valuesSet = getSortValuesSet(txn, entryID, values, types); |
| | | int pos = valuesSet.binarySearch(entryID, values, types); |
| | | int pos = valuesSet.binarySearch(entryID, values); |
| | | return pos >= 0; |
| | | } |
| | | |
| | |
| | | ByteString[] values = getSortValues(entry); |
| | | AttributeType[] types = getSortTypes(); |
| | | DatabaseEntry key = new DatabaseEntry(); |
| | | OperationStatus status; |
| | | LockMode lockMode = LockMode.RMW; |
| | | DatabaseEntry data = new DatabaseEntry(); |
| | | |
| | | Cursor cursor = openCursor(txn, CursorConfig.READ_COMMITTED); |
| | | try |
| | | { |
| | | key.setData(encodeKey(entryID, values, types)); |
| | | status = cursor.getSearchKeyRange(key, data,lockMode); |
| | | } |
| | | finally |
| | | { |
| | | cursor.close(); |
| | | } |
| | | |
| | | SortValuesSet sortValuesSet; |
| | | if(status != OperationStatus.SUCCESS) |
| | | { |
| | | // There are no records in the database |
| | | if(logger.isTraceEnabled()) |
| | | { |
| | | logger.trace("No sort values set exist in VLV vlvIndex %s. " + |
| | | "Creating unbound set.", config.getName()); |
| | | } |
| | | sortValuesSet = new SortValuesSet(this); |
| | | key.setData(new byte[0]); |
| | | } |
| | | else |
| | | { |
| | | if(logger.isTraceEnabled()) |
| | | { |
| | | StringBuilder searchKeyHex = new StringBuilder(); |
| | | StaticUtils.byteArrayToHexPlusAscii(searchKeyHex, key.getData(), 4); |
| | | StringBuilder foundKeyHex = new StringBuilder(); |
| | | StaticUtils.byteArrayToHexPlusAscii(foundKeyHex, key.getData(), 4); |
| | | logger.trace("Retrieved a sort values set in VLV vlvIndex " + |
| | | "%s\nSearch Key:%s\nFound Key:%s\n", |
| | | config.getName(), |
| | | searchKeyHex, |
| | | foundKeyHex); |
| | | } |
| | | sortValuesSet = new SortValuesSet(key.getData(), data.getData(), |
| | | this); |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | key.setData(encodeKey(entryID, values, types)); |
| | | SortValuesSet sortValuesSet = |
| | | getSortValuesSet(txn, key, data, LockMode.RMW); |
| | | boolean success = sortValuesSet.add(entryID, values, types); |
| | | |
| | | int newSize = sortValuesSet.size(); |
| | | if(newSize >= sortedSetCapacity) |
| | | { |
| | | SortValuesSet splitSortValuesSet = sortValuesSet.split(newSize / 2); |
| | | byte[] splitAfter = splitSortValuesSet.toDatabase(); |
| | | key.setData(splitSortValuesSet.getKeyBytes()); |
| | | data.setData(splitAfter); |
| | | put(txn, key, data); |
| | | byte[] after = sortValuesSet.toDatabase(); |
| | | key.setData(sortValuesSet.getKeyBytes()); |
| | | data.setData(after); |
| | | put(txn, key, data); |
| | | put(txn, key, data, splitSortValuesSet); // splitAfter |
| | | put(txn, key, data, sortValuesSet); // after |
| | | |
| | | if(logger.isTraceEnabled()) |
| | | { |
| | |
| | | } |
| | | else |
| | | { |
| | | byte[] after = sortValuesSet.toDatabase(); |
| | | data.setData(after); |
| | | data.setData(sortValuesSet.toDatabase()); // after |
| | | put(txn, key, data); |
| | | // TODO: What about phantoms? |
| | | } |
| | |
| | | return success; |
| | | } |
| | | |
| | | private void put(Transaction txn, DatabaseEntry key, DatabaseEntry data, |
| | | SortValuesSet set) throws DirectoryException |
| | | { |
| | | key.setData(set.getKeyBytes()); |
| | | data.setData(set.toDatabase()); |
| | | put(txn, key, data); |
| | | } |
| | | |
| | | /** |
| | | * Gets the types of the attribute values to sort. |
| | | * |
| | |
| | | AttributeType[] types = new AttributeType[sortKeys.length]; |
| | | for (int i = 0; i < sortKeys.length; i++) |
| | | { |
| | | SortKey sortKey = sortKeys[i]; |
| | | types[i] = sortKey.getAttributeType(); |
| | | types[i] = sortKeys[i].getAttributeType(); |
| | | } |
| | | return types; |
| | | } |
| | |
| | | ByteString[] values = getSortValues(entry); |
| | | AttributeType[] types = getSortTypes(); |
| | | DatabaseEntry key = new DatabaseEntry(); |
| | | OperationStatus status; |
| | | LockMode lockMode = LockMode.RMW; |
| | | DatabaseEntry data = new DatabaseEntry(); |
| | | |
| | | Cursor cursor = openCursor(txn, CursorConfig.READ_COMMITTED); |
| | | |
| | | try |
| | | { |
| | | key.setData(encodeKey(entryID, values, types)); |
| | | status = cursor.getSearchKeyRange(key, data,lockMode); |
| | | } |
| | | finally |
| | | { |
| | | cursor.close(); |
| | | } |
| | | |
| | | key.setData(encodeKey(entryID, values, types)); |
| | | OperationStatus status = getSearchKeyRange(txn, key, data, LockMode.RMW); |
| | | if(status == OperationStatus.SUCCESS) |
| | | { |
| | | if(logger.isTraceEnabled()) |
| | | { |
| | | StringBuilder searchKeyHex = new StringBuilder(); |
| | | StaticUtils.byteArrayToHexPlusAscii(searchKeyHex, key.getData(), 4); |
| | | StringBuilder foundKeyHex = new StringBuilder(); |
| | | StaticUtils.byteArrayToHexPlusAscii(foundKeyHex, key.getData(), 4); |
| | | logger.trace("Retrieved a sort values set in VLV vlvIndex " + |
| | | "%s\nSearch Key:%s\nFound Key:%s\n", |
| | | config.getName(), |
| | | searchKeyHex, |
| | | foundKeyHex); |
| | | logSearchKeyResult(key); |
| | | } |
| | | SortValuesSet sortValuesSet = new SortValuesSet(key.getData(), data.getData(), this); |
| | | boolean success = sortValuesSet.remove(entryID, values, types); |
| | | boolean success = sortValuesSet.remove(entryID, values); |
| | | byte[] after = sortValuesSet.toDatabase(); |
| | | |
| | | if(after == null) |
| | |
| | | return false; |
| | | } |
| | | |
| | | private OperationStatus getSearchKeyRange(Transaction txn, DatabaseEntry key, |
| | | DatabaseEntry data, LockMode lockMode) |
| | | { |
| | | Cursor cursor = openCursor(txn, CursorConfig.READ_COMMITTED); |
| | | try |
| | | { |
| | | return cursor.getSearchKeyRange(key, data, lockMode); |
| | | } |
| | | finally |
| | | { |
| | | cursor.close(); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Update the vlvIndex with the specified values to add and delete. |
| | | * |
| | |
| | | } |
| | | |
| | | DatabaseEntry key = new DatabaseEntry(); |
| | | OperationStatus status; |
| | | LockMode lockMode = LockMode.RMW; |
| | | DatabaseEntry data = new DatabaseEntry(); |
| | | SortValuesSet sortValuesSet; |
| | | Iterator<SortValues> aValues = null; |
| | | Iterator<SortValues> dValues = null; |
| | | SortValues av = null; |
| | |
| | | break; |
| | | } |
| | | |
| | | Cursor cursor = openCursor(txn, CursorConfig.READ_COMMITTED); |
| | | |
| | | try |
| | | { |
| | | status = cursor.getSearchKeyRange(key, data,lockMode); |
| | | } |
| | | finally |
| | | { |
| | | cursor.close(); |
| | | } |
| | | |
| | | if(status != OperationStatus.SUCCESS) |
| | | { |
| | | // There are no records in the database |
| | | if(logger.isTraceEnabled()) |
| | | { |
| | | logger.trace("No sort values set exist in VLV vlvIndex %s. " + |
| | | "Creating unbound set.", config.getName()); |
| | | } |
| | | sortValuesSet = new SortValuesSet(this); |
| | | key.setData(new byte[0]); |
| | | } |
| | | else |
| | | { |
| | | if(logger.isTraceEnabled()) |
| | | { |
| | | StringBuilder searchKeyHex = new StringBuilder(); |
| | | StaticUtils.byteArrayToHexPlusAscii(searchKeyHex, key.getData(), 4); |
| | | StringBuilder foundKeyHex = new StringBuilder(); |
| | | StaticUtils.byteArrayToHexPlusAscii(foundKeyHex, key.getData(), 4); |
| | | logger.trace("Retrieved a sort values set in VLV vlvIndex " + |
| | | "%s\nSearch Key:%s\nFound Key:%s\n", |
| | | config.getName(), |
| | | searchKeyHex, |
| | | foundKeyHex); |
| | | } |
| | | sortValuesSet = new SortValuesSet(key.getData(), data.getData(), |
| | | this); |
| | | } |
| | | |
| | | final SortValuesSet sortValuesSet = getSortValuesSet(txn, data, data, LockMode.RMW); |
| | | int oldSize = sortValuesSet.size(); |
| | | if(key.getData().length == 0) |
| | | { |
| | |
| | | while(av != null) |
| | | { |
| | | sortValuesSet.add(av.getEntryID(), av.getValues(), av.getTypes()); |
| | | aValues.remove(); |
| | | if(aValues.hasNext()) |
| | | { |
| | | av = aValues.next(); |
| | | } |
| | | else |
| | | { |
| | | av = null; |
| | | } |
| | | av = moveToNextSortValues(aValues); |
| | | } |
| | | |
| | | while(dv != null) |
| | | { |
| | | sortValuesSet.remove(dv.getEntryID(), dv.getValues(), dv.getTypes()); |
| | | dValues.remove(); |
| | | if(dValues.hasNext()) |
| | | { |
| | | dv = dValues.next(); |
| | | } |
| | | else |
| | | { |
| | | dv = null; |
| | | } |
| | | sortValuesSet.remove(dv.getEntryID(), dv.getValues()); |
| | | dv = moveToNextSortValues(dValues); |
| | | } |
| | | } |
| | | else |
| | |
| | | while(av != null && av.compareTo(maxValues) <= 0) |
| | | { |
| | | sortValuesSet.add(av.getEntryID(), av.getValues(), av.getTypes()); |
| | | aValues.remove(); |
| | | if(aValues.hasNext()) |
| | | { |
| | | av = aValues.next(); |
| | | } |
| | | else |
| | | { |
| | | av = null; |
| | | } |
| | | av = moveToNextSortValues(aValues); |
| | | } |
| | | |
| | | while(dv != null && dv.compareTo(maxValues) <= 0) |
| | | { |
| | | sortValuesSet.remove(dv.getEntryID(), dv.getValues(), dv.getTypes()); |
| | | dValues.remove(); |
| | | if(dValues.hasNext()) |
| | | { |
| | | dv = dValues.next(); |
| | | } |
| | | else |
| | | { |
| | | dv = null; |
| | | } |
| | | sortValuesSet.remove(dv.getEntryID(), dv.getValues()); |
| | | dv = moveToNextSortValues(dValues); |
| | | } |
| | | } |
| | | |
| | |
| | | if(newSize >= sortedSetCapacity) |
| | | { |
| | | SortValuesSet splitSortValuesSet = sortValuesSet.split(newSize / 2); |
| | | byte[] splitAfter = splitSortValuesSet.toDatabase(); |
| | | key.setData(splitSortValuesSet.getKeyBytes()); |
| | | data.setData(splitAfter); |
| | | put(txn, key, data); |
| | | byte[] after = sortValuesSet.toDatabase(); |
| | | key.setData(sortValuesSet.getKeyBytes()); |
| | | data.setData(after); |
| | | put(txn, key, data); |
| | | put(txn, key, data, splitSortValuesSet); // splitAfter |
| | | put(txn, key, data, sortValuesSet); // after |
| | | |
| | | if(logger.isTraceEnabled()) |
| | | { |
| | |
| | | } |
| | | } |
| | | |
| | | private SortValues moveToNextSortValues(Iterator<SortValues> sortValues) |
| | | { |
| | | sortValues.remove(); |
| | | if (sortValues.hasNext()) |
| | | { |
| | | return sortValues.next(); |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | private byte[] encodeKey(SortValues sv) throws DirectoryException |
| | | { |
| | | return encodeKey(sv.getEntryID(), sv.getValues(), sv.getTypes()); |
| | |
| | | StringBuilder debugBuilder) |
| | | throws DirectoryException, DatabaseException |
| | | { |
| | | if(!trusted || rebuildRunning) |
| | | { |
| | | return null; |
| | | } |
| | | if(!searchOperation.getBaseDN().equals(baseDN)) |
| | | { |
| | | return null; |
| | | } |
| | | if(!searchOperation.getScope().equals(scope)) |
| | | { |
| | | return null; |
| | | } |
| | | if(!searchOperation.getFilter().equals(filter)) |
| | | { |
| | | return null; |
| | | } |
| | | if(!sortControl.getSortOrder().equals(this.sortOrder)) |
| | | if (!trusted || rebuildRunning |
| | | || !searchOperation.getBaseDN().equals(baseDN) |
| | | || !searchOperation.getScope().equals(scope) |
| | | || !searchOperation.getFilter().equals(filter) |
| | | || !sortControl.getSortOrder().equals(sortOrder)) |
| | | { |
| | | return null; |
| | | } |
| | |
| | | int count = 1 + beforeCount + afterCount; |
| | | selectedIDs = new long[count]; |
| | | |
| | | DatabaseEntry key = new DatabaseEntry(); |
| | | OperationStatus status; |
| | | LockMode lockMode = LockMode.DEFAULT; |
| | | DatabaseEntry data = new DatabaseEntry(); |
| | | |
| | | Cursor cursor = openCursor(txn, CursorConfig.READ_COMMITTED); |
| | | |
| | | try |
| | | { |
| | | DatabaseEntry key = new DatabaseEntry(); |
| | | DatabaseEntry data = new DatabaseEntry(); |
| | | LockMode lockMode = LockMode.DEFAULT; |
| | | //Locate the set that contains the target entry. |
| | | int cursorCount = 0; |
| | | int selectedPos = 0; |
| | | status = cursor.getFirst(key, data,lockMode); |
| | | OperationStatus status = cursor.getFirst(key, data, lockMode); |
| | | while(status == OperationStatus.SUCCESS) |
| | | { |
| | | if(logger.isTraceEnabled()) |
| | | { |
| | | StringBuilder searchKeyHex = new StringBuilder(); |
| | | StaticUtils.byteArrayToHexPlusAscii(searchKeyHex, key.getData(), |
| | | 4); |
| | | StringBuilder foundKeyHex = new StringBuilder(); |
| | | StaticUtils.byteArrayToHexPlusAscii(foundKeyHex, key.getData(), |
| | | 4); |
| | | logger.trace("Retrieved a sort values set in VLV " + |
| | | "vlvIndex %s\nSearch Key:%s\nFound Key:%s\n", |
| | | config.getName(), |
| | | searchKeyHex, |
| | | foundKeyHex); |
| | | logSearchKeyResult(key); |
| | | } |
| | | long[] IDs = SortValuesSet.getEncodedIDs(data.getData(), 0); |
| | | for(int i = startPos + selectedPos - cursorCount; |
| | |
| | | int includedAfterCount = 0; |
| | | LinkedList<EntryID> idList = new LinkedList<EntryID>(); |
| | | DatabaseEntry key = new DatabaseEntry(); |
| | | OperationStatus status; |
| | | LockMode lockMode = LockMode.DEFAULT; |
| | | DatabaseEntry data = new DatabaseEntry(); |
| | | |
| | | Cursor cursor = openCursor(txn, CursorConfig.READ_COMMITTED); |
| | | |
| | | try |
| | | { |
| | | LockMode lockMode = LockMode.DEFAULT; |
| | | ByteSequence vBytes = vlvRequest.getGreaterThanOrEqualAssertion(); |
| | | ByteStringBuilder keyBytes = |
| | | new ByteStringBuilder(vBytes.length() + 4); |
| | |
| | | vBytes.copyTo(keyBytes); |
| | | |
| | | key.setData(keyBytes.getBackingArray(), 0, keyBytes.length()); |
| | | status = cursor.getSearchKeyRange(key, data, lockMode); |
| | | OperationStatus status = cursor.getSearchKeyRange(key, data, lockMode); |
| | | if(status == OperationStatus.SUCCESS) |
| | | { |
| | | if(logger.isTraceEnabled()) |
| | | { |
| | | StringBuilder searchKeyHex = new StringBuilder(); |
| | | StaticUtils.byteArrayToHexPlusAscii(searchKeyHex, key.getData(), |
| | | 4); |
| | | StringBuilder foundKeyHex = new StringBuilder(); |
| | | StaticUtils.byteArrayToHexPlusAscii(foundKeyHex, key.getData(), |
| | | 4); |
| | | logger.trace("Retrieved a sort values set in VLV " + |
| | | "vlvIndex %s\nSearch Key:%s\nFound Key:%s\n", |
| | | config.getName(), |
| | | searchKeyHex, |
| | | foundKeyHex); |
| | | logSearchKeyResult(key); |
| | | } |
| | | SortValuesSet sortValuesSet = |
| | | new SortValuesSet(key.getData(), data.getData(), this); |
| | | ByteString[] assertionValue = new ByteString[] { |
| | | vlvRequest.getGreaterThanOrEqualAssertion() |
| | | }; |
| | | AttributeType[] assertionType = new AttributeType[] { |
| | | sortOrder.getSortKeys()[0].getAttributeType() |
| | | }; |
| | | |
| | | int adjustedTargetOffset = |
| | | sortValuesSet.binarySearch(-1, assertionValue, assertionType); |
| | | int adjustedTargetOffset = sortValuesSet.binarySearch( |
| | | -1, vlvRequest.getGreaterThanOrEqualAssertion()); |
| | | if(adjustedTargetOffset < 0) |
| | | { |
| | | // For a negative return value r, the vlvIndex -(r+1) gives the |
| | |
| | | } |
| | | |
| | | status = cursor.getPrev(key, data, lockMode); |
| | | |
| | | if(status != OperationStatus.SUCCESS) |
| | | { |
| | | break; |
| | |
| | | |
| | | if(includedBeforeCount < beforeCount) |
| | | { |
| | | lastIDs = |
| | | SortValuesSet.getEncodedIDs(data.getData(), 0); |
| | | lastIDs = SortValuesSet.getEncodedIDs(data.getData(), 0); |
| | | lastOffset = lastIDs.length - 1; |
| | | targetOffset += lastIDs.length; |
| | | } |
| | |
| | | } |
| | | |
| | | status = cursor.getNext(key, data, lockMode); |
| | | |
| | | if(status != OperationStatus.SUCCESS) |
| | | { |
| | | break; |
| | | } |
| | | |
| | | lastIDs = |
| | | SortValuesSet.getEncodedIDs(data.getData(), 0); |
| | | lastIDs = SortValuesSet.getEncodedIDs(data.getData(), 0); |
| | | lastOffset = 0; |
| | | afterIDCount += lastIDs.length; |
| | | } |
| | |
| | | LinkedList<long[]> idSets = new LinkedList<long[]>(); |
| | | int currentCount = 0; |
| | | DatabaseEntry key = new DatabaseEntry(); |
| | | OperationStatus status; |
| | | LockMode lockMode = LockMode.RMW; |
| | | DatabaseEntry data = new DatabaseEntry(); |
| | | |
| | | Cursor cursor = openCursor(txn, CursorConfig.READ_COMMITTED); |
| | | |
| | | try |
| | | { |
| | | status = cursor.getFirst(key, data, lockMode); |
| | | LockMode lockMode = LockMode.RMW; |
| | | OperationStatus status = cursor.getFirst(key, data, lockMode); |
| | | while(status == OperationStatus.SUCCESS) |
| | | { |
| | | if(logger.isTraceEnabled()) |
| | | { |
| | | StringBuilder searchKeyHex = new StringBuilder(); |
| | | StaticUtils.byteArrayToHexPlusAscii(searchKeyHex, key.getData(), 4); |
| | | StringBuilder foundKeyHex = new StringBuilder(); |
| | | StaticUtils.byteArrayToHexPlusAscii(foundKeyHex, key.getData(), 4); |
| | | logger.trace("Retrieved a sort values set in VLV vlvIndex " + |
| | | "%s\nSearch Key:%s\nFound Key:%s\n", |
| | | config.getName(), |
| | | searchKeyHex, |
| | | foundKeyHex); |
| | | logSearchKeyResult(key); |
| | | } |
| | | long[] ids = SortValuesSet.getEncodedIDs(data.getData(), 0); |
| | | idSets.add(ids); |
| | |
| | | for (int i=0; i < sortKeys.length; i++) |
| | | { |
| | | SortKey sortKey = sortKeys[i]; |
| | | AttributeType attrType = sortKey.getAttributeType(); |
| | | List<Attribute> attrList = entry.getAttribute(attrType); |
| | | List<Attribute> attrList = entry.getAttribute(sortKey.getAttributeType()); |
| | | if (attrList != null) |
| | | { |
| | | ByteString sortValue = null; |
| | | |
| | | // There may be multiple versions of this attribute in the target entry |
| | | // (e.g., with different sets of options), and it may also be a |
| | | // multivalued attribute. In that case, we need to find the value that |
| | |
| | | // in ascending order, we want to find the lowest value; for sorting in |
| | | // descending order, we want to find the highest value). This is |
| | | // handled by the SortKey.compareValues method. |
| | | ByteString sortValue = null; |
| | | for (Attribute a : attrList) |
| | | { |
| | | for (ByteString v : a) |
| | | { |
| | | if (sortValue == null) |
| | | { |
| | | sortValue = v; |
| | | } |
| | | else if (sortKey.compareValues(v, sortValue) < 0) |
| | | if (sortValue == null || sortKey.compareValues(v, sortValue) < 0) |
| | | { |
| | | sortValue = v; |
| | | } |
| | |
| | | * @return The sort values represented by the key bytes. |
| | | * @throws DirectoryException If a Directory Server error occurs. |
| | | */ |
| | | SortValues decodeKey(byte[] keyBytes) |
| | | throws DirectoryException |
| | | SortValues decodeKey(byte[] keyBytes) throws DirectoryException |
| | | { |
| | | if(keyBytes == null || keyBytes.length == 0) |
| | | { |
| | |
| | | vBytesPos += valueLength; |
| | | } |
| | | |
| | | // FIXME: Should pos+offset method for decoding IDs be added to |
| | | // JebFormat? |
| | | long v = 0; |
| | | for (int i = vBytesPos; i < keyBytes.length; i++) |
| | | { |
| | | v <<= 8; |
| | | v |= (keyBytes[i] & 0xFF); |
| | | } |
| | | |
| | | return new SortValues(new EntryID(v), attributeValues, sortOrder); |
| | | final long id = JebFormat.toLong(keyBytes, vBytesPos, keyBytes.length); |
| | | return new SortValues(new EntryID(id), attributeValues, sortOrder); |
| | | } |
| | | |
| | | /** |
| | |
| | | { |
| | | try |
| | | { |
| | | this.filter = |
| | | SearchFilter.createFilterFromString(cfg.getFilter()); |
| | | this.filter = SearchFilter.createFilterFromString(cfg.getFilter()); |
| | | } |
| | | catch(Exception e) |
| | | { |
| | |
| | | |
| | | String[] sortAttrs = cfg.getSortOrder().split(" "); |
| | | SortKey[] sortKeys = new SortKey[sortAttrs.length]; |
| | | MatchingRule[] orderingRules = |
| | | new MatchingRule[sortAttrs.length]; |
| | | MatchingRule[] orderingRules = new MatchingRule[sortAttrs.length]; |
| | | boolean[] ascending = new boolean[sortAttrs.length]; |
| | | for(int i = 0; i < sortAttrs.length; i++) |
| | | { |
| | |
| | | } |
| | | |
| | | // Update sort set capacity only if changed. |
| | | if(config.getMaxBlockSize() != |
| | | cfg.getMaxBlockSize()) |
| | | if (config.getMaxBlockSize() != cfg.getMaxBlockSize()) |
| | | { |
| | | this.sortedSetCapacity = cfg.getMaxBlockSize(); |
| | | |
| | | // Require admin action only if the new capacity is larger. Otherwise, |
| | | // we will lazyly update the sorted sets. |
| | | if(config.getMaxBlockSize() < |
| | | cfg.getMaxBlockSize()) |
| | | if (config.getMaxBlockSize() < cfg.getMaxBlockSize()) |
| | | { |
| | | adminActionRequired = true; |
| | | } |
| | |
| | | { |
| | | try |
| | | { |
| | | this.filter = |
| | | SearchFilter.createFilterFromString(cfg.getFilter()); |
| | | this.filter = SearchFilter.createFilterFromString(cfg.getFilter()); |
| | | adminActionRequired = true; |
| | | } |
| | | catch(Exception e) |
| | |
| | | } |
| | | |
| | | // Update the sort order only if changed. |
| | | if(!config.getSortOrder().equals( |
| | | cfg.getSortOrder())) |
| | | if (!config.getSortOrder().equals(cfg.getSortOrder())) |
| | | { |
| | | String[] sortAttrs = cfg.getSortOrder().split(" "); |
| | | SortKey[] sortKeys = new SortKey[sortAttrs.length]; |
| | | MatchingRule[] orderingRules = |
| | | new MatchingRule[sortAttrs.length]; |
| | | MatchingRule[] orderingRules = new MatchingRule[sortAttrs.length]; |
| | | boolean[] ascending = new boolean[sortAttrs.length]; |
| | | for(int i = 0; i < sortAttrs.length; i++) |
| | | { |
| | |
| | | if(adminActionRequired) |
| | | { |
| | | trusted = false; |
| | | LocalizableMessage message = NOTE_JEB_INDEX_ADD_REQUIRES_REBUILD.get(name); |
| | | messages.add(message); |
| | | messages.add(NOTE_JEB_INDEX_ADD_REQUIRES_REBUILD.get(name)); |
| | | try |
| | | { |
| | | state.putIndexTrustState(null, this, false); |
| | |
| | | import org.forgerock.opendj.ldap.DecodeException; |
| | | import org.forgerock.opendj.ldap.ResultCode; |
| | | import org.opends.server.api.MatchingRule; |
| | | import org.opends.server.types.AttributeType; |
| | | import org.opends.server.types.DirectoryException; |
| | | |
| | | import com.sleepycat.je.DatabaseException; |
| | |
| | | * @param ascending The array of booleans indicating the ordering for |
| | | * each value. |
| | | */ |
| | | public VLVKeyComparator(MatchingRule[] orderingRules, |
| | | boolean[] ascending) |
| | | public VLVKeyComparator(MatchingRule[] orderingRules, boolean[] ascending) |
| | | { |
| | | this.orderingRules = orderingRules; |
| | | this.ascending = ascending; |
| | |
| | | |
| | | if(b1Pos + 8 <= b1.length && b2Pos + 8 <= b2.length) |
| | | { |
| | | long b1ID = 0; |
| | | for (int i = b1Pos; i < b1Pos + 8; i++) |
| | | { |
| | | b1ID <<= 8; |
| | | b1ID |= (b1[i] & 0xFF); |
| | | } |
| | | |
| | | long b2ID = 0; |
| | | for (int i = b2Pos; i < b2Pos + 8; i++) |
| | | { |
| | | b2ID <<= 8; |
| | | b2ID |= (b2[i] & 0xFF); |
| | | } |
| | | long b1ID = JebFormat.toLong(b1, b1Pos, b1Pos + 8); |
| | | long b2ID = JebFormat.toLong(b2, b2Pos, b2Pos + 8); |
| | | |
| | | long idDifference = (b1ID - b2ID); |
| | | if (idDifference < 0) |
| | |
| | | } |
| | | |
| | | // If we've gotten here, then we can't tell the difference between the sets |
| | | // of available values and entry IDs are not all available, so just return |
| | | // 0 |
| | | // of available values and entry IDs are not all available, so just return 0 |
| | | return 0; |
| | | |
| | | } |
| | | |
| | | /** |
| | |
| | | * |
| | | * @param set The sort values set to containing the values. |
| | | * @param index The index of the values in the set. |
| | | * @param entryID The entry ID to use in the comparasion. |
| | | * @param values The values to use in the comparasion. |
| | | * @param types The types of the values to use in the comparasion. |
| | | * |
| | | * @param entryID The entry ID to use in the comparison. |
| | | * @param values The values to use in the comparison. |
| | | * @return A negative integer if the values in the set should come before |
| | | * the given values in ascending order, a positive integer if |
| | | * the values in the set should come after the given values in |
| | |
| | | * associated equality matching rule). |
| | | */ |
| | | public int compare(SortValuesSet set, int index, long entryID, |
| | | ByteString[] values, AttributeType[] types) throws DatabaseException, |
| | | DirectoryException |
| | | ByteString[] values) throws DatabaseException, DirectoryException |
| | | { |
| | | for (int j=0; j < orderingRules.length; j++) |
| | | { |
| | |
| | | { |
| | | try |
| | | { |
| | | final MatchingRule eqRule = types[j].getEqualityMatchingRule(); |
| | | b2Bytes = eqRule.normalizeAttributeValue(values[j]); |
| | | b2Bytes = orderingRules[j].normalizeAttributeValue(values[j]); |
| | | } |
| | | catch (DecodeException e) |
| | | { |
| | |
| | | import java.util.Set; |
| | | |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | | import org.forgerock.opendj.ldap.DecodeException; |
| | | import org.opends.server.api.MatchingRule; |
| | | |
| | | import static org.opends.server.util.StaticUtils.*; |
| | | |
| | |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public int hashCode() |
| | | { |
| | | int hashCode = getAttributeType().hashCode(); |
| | | for (ByteString value : this) |
| | | { |
| | | hashCode += value.hashCode(); |
| | | try |
| | | { |
| | | MatchingRule eqRule = getAttributeType().getEqualityMatchingRule(); |
| | | hashCode += eqRule.normalizeAttributeValue(value).hashCode(); |
| | | } |
| | | catch (DecodeException e) |
| | | { |
| | | hashCode += value.hashCode(); |
| | | } |
| | | } |
| | | return hashCode; |
| | | } |
| | |
| | | { |
| | | String noption = toLowerCase(option); |
| | | |
| | | // Cannot use Set.contains() because the options are not |
| | | // normalized. |
| | | // Cannot use Set.contains() because the options are not normalized. |
| | | for (String o : getOptions()) |
| | | { |
| | | String no = toLowerCase(o); |
| | |
| | | return false; |
| | | } |
| | | |
| | | // Cannot use Set.containsAll() because the set of options are |
| | | // not normalized. |
| | | // Cannot use Set.containsAll() because the set of options are not normalized. |
| | | for (String option : options) |
| | | { |
| | | if (!hasOption(option)) |
| | |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | return true; |
| | | } |
| | | |
| | |
| | | * Indicates whether this attribute has any value(s) that are |
| | | * approximately equal to the provided value. |
| | | * |
| | | * @param value |
| | | * The value for which to make the determination. |
| | | * @param assertionValue |
| | | * The assertion value for which to make the determination. |
| | | * @return <CODE>UNDEFINED</CODE> if this attribute does not have |
| | | * an approximate matching rule, <CODE>TRUE</CODE> if at |
| | | * least one value is approximately equal to the provided |
| | | * value, or <CODE>false</CODE> otherwise. |
| | | */ |
| | | ConditionResult approximatelyEqualTo(ByteString value); |
| | | ConditionResult approximatelyEqualTo(ByteString assertionValue); |
| | | |
| | | |
| | | |
| | |
| | | |
| | | |
| | | /** |
| | | * Indicates whether this attribute matches the specified assertion value. |
| | | * |
| | | * @param assertionValue |
| | | * The assertion value for which to make the determination. |
| | | * @return <CODE>true</CODE> if this attribute matches the specified assertion |
| | | * value, or <CODE>false</CODE> if not. |
| | | */ |
| | | ConditionResult matchesEqualityAssertion(ByteString assertionValue); |
| | | |
| | | |
| | | |
| | | /** |
| | | * Indicates whether the provided object is an attribute that is |
| | | * equal to this attribute. It will be considered equal if the |
| | | * attribute type, set of values, and set of options are equal. |
| | |
| | | * Indicates whether this attribute has any value(s) that are |
| | | * greater than or equal to the provided value. |
| | | * |
| | | * @param value |
| | | * The value for which to make the determination. |
| | | * @param assertionValue |
| | | * The assertion value for which to make the determination. |
| | | * @return <CODE>UNDEFINED</CODE> if this attribute does not have |
| | | * an ordering matching rule, <CODE>TRUE</CODE> if at |
| | | * least one value is greater than or equal to the provided |
| | | * value, or <CODE>false</CODE> otherwise. |
| | | * assertion value, or <CODE>false</CODE> otherwise. |
| | | */ |
| | | ConditionResult greaterThanOrEqualTo(ByteString value); |
| | | ConditionResult greaterThanOrEqualTo(ByteString assertionValue); |
| | | |
| | | |
| | | |
| | |
| | | * Indicates whether this attribute has any value(s) that are less |
| | | * than or equal to the provided value. |
| | | * |
| | | * @param value |
| | | * The value for which to make the determination. |
| | | * @param assertionValue |
| | | * The assertion value for which to make the determination. |
| | | * @return <CODE>UNDEFINED</CODE> if this attribute does not have |
| | | * an ordering matching rule, <CODE>TRUE</CODE> if at |
| | | * least one value is less than or equal to the provided |
| | | * value, or <CODE>false</CODE> otherwise. |
| | | * assertion value, or <CODE>false</CODE> otherwise. |
| | | */ |
| | | ConditionResult lessThanOrEqualTo(ByteString value); |
| | | ConditionResult lessThanOrEqualTo(ByteString assertionValue); |
| | | |
| | | |
| | | |
| | |
| | | import java.util.Collections; |
| | | import java.util.Iterator; |
| | | import java.util.LinkedHashSet; |
| | | import java.util.LinkedHashMap; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.Map.Entry; |
| | |
| | | // The name of this attribute as provided by the end user. |
| | | private final String name; |
| | | |
| | | // The unmodifiable set of values for this attribute. |
| | | /** |
| | | * The unmodifiable map of values for this attribute. The key is the |
| | | * attribute value normalized according to the equality matching rule and |
| | | * the value is the non normalized value. |
| | | */ |
| | | private final Map<ByteString, ByteString> values; |
| | | |
| | | |
| | |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public final ConditionResult approximatelyEqualTo(ByteString value) |
| | | public final ConditionResult approximatelyEqualTo(ByteString assertionValue) |
| | | { |
| | | MatchingRule matchingRule = attributeType.getApproximateMatchingRule(); |
| | | if (matchingRule == null) |
| | |
| | | Assertion assertion = null; |
| | | try |
| | | { |
| | | assertion = matchingRule.getAssertion(value); |
| | | assertion = matchingRule.getAssertion(assertionValue); |
| | | } |
| | | catch (Exception e) |
| | | { |
| | |
| | | return values.containsKey(normalize(attributeType, value)); |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public ConditionResult matchesEqualityAssertion(ByteString assertionValue) |
| | | { |
| | | try |
| | | { |
| | | MatchingRule eqRule = getAttributeType().getEqualityMatchingRule(); |
| | | final Assertion assertion = eqRule.getAssertion(assertionValue); |
| | | for (ByteString normalizedValue : values.keySet()) |
| | | { |
| | | if (assertion.matches(normalizedValue).toBoolean()) |
| | | { |
| | | return ConditionResult.TRUE; |
| | | } |
| | | } |
| | | return ConditionResult.FALSE; |
| | | } |
| | | catch (DecodeException e) |
| | | { |
| | | return ConditionResult.UNDEFINED; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public final ConditionResult greaterThanOrEqualTo(ByteString value) |
| | | public final ConditionResult greaterThanOrEqualTo(ByteString assertionValue) |
| | | { |
| | | MatchingRule matchingRule = attributeType.getOrderingMatchingRule(); |
| | | if (matchingRule == null) |
| | |
| | | Assertion assertion; |
| | | try |
| | | { |
| | | assertion = matchingRule.getGreaterOrEqualAssertion(value); |
| | | assertion = matchingRule.getGreaterOrEqualAssertion(assertionValue); |
| | | } |
| | | catch (DecodeException e) |
| | | { |
| | |
| | | { |
| | | logger.traceException(e); |
| | | // We couldn't normalize one of the attribute values. If we |
| | | // can't find a definite match, then we should return |
| | | // "undefined". |
| | | // can't find a definite match, then we should return "undefined". |
| | | result = ConditionResult.UNDEFINED; |
| | | } |
| | | } |
| | |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public final ConditionResult lessThanOrEqualTo(ByteString value) |
| | | public final ConditionResult lessThanOrEqualTo(ByteString assertionValue) |
| | | { |
| | | MatchingRule matchingRule = attributeType.getOrderingMatchingRule(); |
| | | if (matchingRule == null) |
| | |
| | | Assertion assertion; |
| | | try |
| | | { |
| | | assertion = matchingRule.getLessOrEqualAssertion(value); |
| | | assertion = matchingRule.getLessOrEqualAssertion(assertionValue); |
| | | } |
| | | catch (DecodeException e) |
| | | { |
| | |
| | | private final SmallSet<String> options = new SmallSet<String>(); |
| | | |
| | | /** The map of normalized values => values for this attribute. */ |
| | | private LinkedHashMap<ByteString, ByteString> values = |
| | | new LinkedHashMap<ByteString, ByteString>(); |
| | | private Map<ByteString, ByteString> values = |
| | | new SmallMap<ByteString, ByteString>(); |
| | | |
| | | |
| | | |
| | |
| | | * Adds the specified attribute value to this attribute builder if it is not |
| | | * already present. |
| | | * |
| | | * @param value |
| | | * @param attributeValue |
| | | * The {@link ByteString} representation of the attribute value to be |
| | | * added to this attribute builder. |
| | | * @return <code>true</code> if this attribute builder did not already contain |
| | | * the specified attribute value. |
| | | */ |
| | | public boolean add(ByteString value) |
| | | public boolean add(ByteString attributeValue) |
| | | { |
| | | return values.put(normalize(value), value) == null; |
| | | return values.put(normalize(attributeValue), attributeValue) == null; |
| | | } |
| | | |
| | | private ByteString normalize(ByteString value) |
| | | private ByteString normalize(ByteString attributeValue) |
| | | { |
| | | return normalize(attributeType, value); |
| | | return normalize(attributeType, attributeValue); |
| | | } |
| | | |
| | | private static ByteString normalize(AttributeType attributeType, ByteString value) |
| | | private static ByteString normalize(AttributeType attributeType, |
| | | ByteString attributeValue) |
| | | { |
| | | try |
| | | { |
| | | if (attributeType != null) |
| | | { |
| | | final MatchingRule eqRule = attributeType.getEqualityMatchingRule(); |
| | | return eqRule.normalizeAttributeValue(value); |
| | | return eqRule.normalizeAttributeValue(attributeValue); |
| | | } |
| | | } |
| | | catch (DecodeException e) |
| | | { |
| | | // nothing to do here |
| | | } |
| | | return value; |
| | | return attributeValue; |
| | | } |
| | | |
| | | /** |
| | |
| | | else |
| | | { |
| | | newValues = Collections.unmodifiableMap(values); |
| | | values = new LinkedHashMap<ByteString, ByteString>(); |
| | | values = new SmallMap<ByteString, ByteString>(); |
| | | } |
| | | |
| | | // Now create the appropriate attribute based on the options. |
| | |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public ConditionResult approximatelyEqualTo(ByteString value) { |
| | | return attribute.approximatelyEqualTo(value); |
| | | public ConditionResult approximatelyEqualTo(ByteString assertionValue) { |
| | | return attribute.approximatelyEqualTo(assertionValue); |
| | | } |
| | | |
| | | /** |
| | |
| | | return attribute.contains(value); |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public ConditionResult matchesEqualityAssertion(ByteString assertionValue) |
| | | { |
| | | return attribute.matchesEqualityAssertion(assertionValue); |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public ConditionResult greaterThanOrEqualTo(ByteString value) { |
| | | return attribute.greaterThanOrEqualTo(value); |
| | | public ConditionResult greaterThanOrEqualTo(ByteString assertionValue) { |
| | | return attribute.greaterThanOrEqualTo(assertionValue); |
| | | } |
| | | |
| | | /** |
| | |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public ConditionResult lessThanOrEqualTo(ByteString value) { |
| | | return attribute.lessThanOrEqualTo(value); |
| | | public ConditionResult lessThanOrEqualTo(ByteString assertionValue) { |
| | | return attribute.lessThanOrEqualTo(assertionValue); |
| | | } |
| | | |
| | | /** |
| | |
| | | return ConditionResult.UNDEFINED; |
| | | } |
| | | |
| | | ByteString normAssertionValue; |
| | | try |
| | | { |
| | | normAssertionValue = matchingRule.normalizeAssertionValue(assertionValue); |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | logger.traceException(e); |
| | | |
| | | // We can't normalize the assertion value, so the result must be |
| | | // undefined. |
| | | return ConditionResult.UNDEFINED; |
| | | } |
| | | |
| | | // Iterate through all the attributes and see if we can find a match. |
| | | ConditionResult result = ConditionResult.FALSE; |
| | | for (Attribute a : attrs) |
| | | { |
| | | // FIXME next if is incorrect |
| | | if (a.contains(normAssertionValue)) |
| | | final ConditionResult cr = a.matchesEqualityAssertion(assertionValue); |
| | | if (cr == ConditionResult.TRUE) |
| | | { |
| | | if (logger.isTraceEnabled()) |
| | | { |
| | | logger.trace( |
| | | "Returning TRUE for equality component %s in " + |
| | | "filter %s for entry %s", this, completeFilter, entry.getName()); |
| | | "Returning TRUE for equality component %s in filter %s " + |
| | | "for entry %s", this, completeFilter, entry.getName()); |
| | | } |
| | | return ConditionResult.TRUE; |
| | | } |
| | | else if (cr == ConditionResult.UNDEFINED) |
| | | { |
| | | result = ConditionResult.UNDEFINED; |
| | | } |
| | | } |
| | | |
| | | if (logger.isTraceEnabled()) |
| | | { |
| | | logger.trace( |
| | | "Returning FALSE for equality component %s in filter " + |
| | | "%s because entry %s didn't have attribute type %s with value %s", |
| | | this, completeFilter, entry.getName(), attributeType.getNameOrOID(), assertionValue); |
| | | "Returning %s for equality component %s in filter %s " + |
| | | "because entry %s didn't have attribute type %s with value %s", |
| | | result, this, completeFilter, entry.getName(), attributeType.getNameOrOID(), assertionValue); |
| | | } |
| | | return ConditionResult.FALSE; |
| | | return result; |
| | | } |
| | | |
| | | |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt |
| | | * or http://forgerock.org/license/CDDLv1.0.html. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at legal-notices/CDDLv1_0.txt. |
| | | * If applicable, add the following below this CDDL HEADER, with the |
| | | * fields enclosed by brackets "[]" replaced with your own identifying |
| | | * information: |
| | | * Portions Copyright [yyyy] [name of copyright owner] |
| | | * |
| | | * CDDL HEADER END |
| | | * |
| | | * Copyright 2014 ForgeRock AS |
| | | */ |
| | | package org.opends.server.types; |
| | | |
| | | import java.util.*; |
| | | |
| | | /** |
| | | * A small map of values. This map implementation is optimized to use as little |
| | | * memory as possible in the case where there zero or one elements. In addition, |
| | | * any normalization of entriess is delayed until the second entry is added |
| | | * (normalization may be triggered by invoking {@link Object#hashCode()} or |
| | | * {@link Object#equals(Object)}. |
| | | * <p> |
| | | * Null keys are not supported by this map. |
| | | * |
| | | * @param <K> |
| | | * the type of keys maintained by this map |
| | | * @param <V> |
| | | * the type of mapped values |
| | | */ |
| | | public class SmallMap<K, V> extends AbstractMap<K, V> |
| | | { |
| | | |
| | | /** The map of entries if there are more than one. */ |
| | | private LinkedHashMap<K, V> entries; |
| | | |
| | | /** The first key of the Map. */ |
| | | private K firstKey; |
| | | /** The first value of the Map. */ |
| | | private V firstValue; |
| | | |
| | | |
| | | /** Creates a new small map which is initially empty. */ |
| | | public SmallMap() |
| | | { |
| | | // No implementation required. |
| | | } |
| | | |
| | | private void rejectIfNull(Object key) |
| | | { |
| | | if (key == null) |
| | | { |
| | | throw new NullPointerException("null keys are not allowed"); |
| | | } |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public V get(Object key) |
| | | { |
| | | rejectIfNull(key); |
| | | if (entries != null) |
| | | { // >= 2 entries case |
| | | return entries.get(key); |
| | | } |
| | | // 0 and 1 case |
| | | if (firstKey != null && firstKey.equals(key)) |
| | | { |
| | | return firstValue; |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public V put(K key, V value) |
| | | { |
| | | rejectIfNull(key); |
| | | if (entries != null) |
| | | { // >= 2 entries case |
| | | return entries.put(key, value); |
| | | } |
| | | if (firstKey == null) |
| | | { // 0 entries case |
| | | firstKey = key; |
| | | firstValue = value; |
| | | return null; |
| | | } |
| | | // 1 entry case |
| | | if (firstKey.equals(key)) |
| | | { // replace value |
| | | V oldValue = firstValue; |
| | | firstValue = value; |
| | | return oldValue; |
| | | } |
| | | // overflow to the underlying map |
| | | entries = new LinkedHashMap<K, V>(2); |
| | | entries.put(firstKey, firstValue); |
| | | firstKey = null; |
| | | firstValue = null; |
| | | return entries.put(key, value); |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public void putAll(Map<? extends K, ? extends V> m) |
| | | { |
| | | for (Entry<? extends K, ? extends V> entry : m.entrySet()) |
| | | { |
| | | put(entry.getKey(), entry.getValue()); |
| | | } |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public V remove(Object key) |
| | | { |
| | | if (entries != null) |
| | | { |
| | | // Note: if there is one or zero values left we could stop using the map. |
| | | // However, lets assume that if the map was multi-valued before |
| | | // then it may become multi-valued again. |
| | | return entries.remove(key); |
| | | } |
| | | |
| | | if (firstKey != null && firstKey.equals(key)) |
| | | { |
| | | V oldV = firstValue; |
| | | firstKey = null; |
| | | firstValue = null; |
| | | return oldV; |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public boolean containsKey(Object key) |
| | | { |
| | | rejectIfNull(key); |
| | | if (entries != null) |
| | | { |
| | | return entries.containsKey(key); |
| | | } |
| | | return firstKey != null && firstKey.equals(key); |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public boolean containsValue(Object value) |
| | | { |
| | | if (entries != null) |
| | | { |
| | | return entries.containsValue(value); |
| | | } |
| | | if (firstKey == null) |
| | | { |
| | | return false; |
| | | } |
| | | if (firstValue == null) |
| | | { |
| | | return value == null; |
| | | } |
| | | return firstValue.equals(value); |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public void clear() |
| | | { |
| | | firstKey = null; |
| | | firstValue = null; |
| | | entries = null; |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public int size() |
| | | { |
| | | if (entries != null) |
| | | { |
| | | return entries.size(); |
| | | } |
| | | return firstKey != null ? 1 : 0; |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public Set<Entry<K, V>> entrySet() |
| | | { |
| | | if (entries != null) |
| | | { |
| | | return entries.entrySet(); |
| | | } |
| | | if (firstKey == null) |
| | | { |
| | | return Collections.emptySet(); |
| | | } |
| | | |
| | | return new AbstractSet<Entry<K, V>>() |
| | | { |
| | | |
| | | @Override |
| | | public Iterator<Entry<K, V>> iterator() |
| | | { |
| | | return new Iterator<Entry<K, V>>() |
| | | { |
| | | |
| | | private boolean isFirst = true; |
| | | |
| | | @Override |
| | | public boolean hasNext() |
| | | { |
| | | return isFirst; |
| | | } |
| | | |
| | | @Override |
| | | public Entry<K, V> next() |
| | | { |
| | | if (!isFirst) |
| | | { |
| | | throw new NoSuchElementException(); |
| | | } |
| | | isFirst = false; |
| | | return new SimpleEntry<K, V>(firstKey, firstValue); |
| | | } |
| | | |
| | | @Override |
| | | public void remove() |
| | | { |
| | | firstKey = null; |
| | | firstValue = null; |
| | | } |
| | | }; |
| | | } |
| | | |
| | | @Override |
| | | public int size() |
| | | { |
| | | return 1; |
| | | } |
| | | }; |
| | | } |
| | | |
| | | } |
| | |
| | | import org.forgerock.i18n.slf4j.LocalizedLogger; |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | | import org.forgerock.opendj.ldap.ConditionResult; |
| | | import org.forgerock.opendj.ldap.DecodeException; |
| | | import org.forgerock.util.Utils; |
| | | import org.opends.server.api.MatchingRule; |
| | | import org.opends.server.api.VirtualAttributeProvider; |
| | | |
| | | /** |
| | |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public ConditionResult approximatelyEqualTo(ByteString value) |
| | | public ConditionResult approximatelyEqualTo(ByteString assertionValue) |
| | | { |
| | | return provider.approximatelyEqualTo(entry, rule, value); |
| | | return provider.approximatelyEqualTo(entry, rule, assertionValue); |
| | | } |
| | | |
| | | |
| | |
| | | return provider.hasAllValues(entry, rule, values); |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public ConditionResult matchesEqualityAssertion(ByteString assertionValue) |
| | | { |
| | | return provider.matchesEqualityAssertion(entry, rule, assertionValue); |
| | | } |
| | | |
| | | |
| | | /** {@inheritDoc} */ |
| | |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public ConditionResult greaterThanOrEqualTo(ByteString value) |
| | | public ConditionResult greaterThanOrEqualTo(ByteString assertionValue) |
| | | { |
| | | return provider.greaterThanOrEqualTo(entry, rule, value); |
| | | return provider.greaterThanOrEqualTo(entry, rule, assertionValue); |
| | | } |
| | | |
| | | |
| | |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public ConditionResult lessThanOrEqualTo(ByteString value) |
| | | public ConditionResult lessThanOrEqualTo(ByteString assertionValue) |
| | | { |
| | | return provider.lessThanOrEqualTo(entry, rule, value); |
| | | return provider.lessThanOrEqualTo(entry, rule, assertionValue); |
| | | } |
| | | |
| | | |
| | |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public int hashCode() |
| | | { |
| | | int hashCode = getAttributeType().hashCode(); |
| | | for (ByteString value : this) |
| | | { |
| | | try |
| | | { |
| | | final MatchingRule eqRule = attributeType.getEqualityMatchingRule(); |
| | | final ByteString nv = eqRule.normalizeAttributeValue(value); |
| | | hashCode += nv.hashCode(); |
| | | } |
| | | catch (DecodeException e) |
| | | { |
| | | logger.traceException(e); |
| | | } |
| | | } |
| | | return hashCode; |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public void toString(StringBuilder buffer) |
| | | { |
| | | buffer.append("VirtualAttribute("); |
| | |
| | | ByteString[] badValues = new ByteString[values.length]; |
| | | System.arraycopy(values, 1, badValues, 0, values.length - 1); |
| | | badValues[badValues.length-1] = values[0]; |
| | | svs.remove(id, values, types); |
| | | svs.remove(id, values); |
| | | svs.add(id, badValues, types); |
| | | |
| | | vlvIndex.putSortValuesSet(null, svs); |
| | |
| | | SortValuesSet svs = vlvIndex.getSortValuesSet(null, 0, new ByteString[3], types); |
| | | long id = svs.getEntryIDs()[0]; |
| | | Entry entry = eContainer.getID2Entry().get(null, new EntryID(id), LockMode.DEFAULT); |
| | | svs.remove(id, vlvIndex.getSortValues(entry), types); |
| | | svs.remove(id, vlvIndex.getSortValues(entry)); |
| | | |
| | | // Add an incorrectly ordered values. |
| | | SortValuesSet svs2 = svs.split(2); |
| | |
| | | ByteString[] badValues = new ByteString[values.length]; |
| | | System.arraycopy(values, 1, badValues, 0, values.length - 1); |
| | | badValues[badValues.length-1] = values[0]; |
| | | svs.remove(id, values, types); |
| | | svs.remove(id, values); |
| | | svs.add(id, badValues, types); |
| | | |
| | | vlvIndex.putSortValuesSet(null, svs); |
| | |
| | | */ |
| | | package org.opends.server.types; |
| | | |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | | import org.opends.server.DirectoryServerTestCase; |
| | | import org.opends.server.TestCaseUtils; |
| | | import org.opends.server.util.StaticUtils; |
| | | import org.opends.server.util.Base64; |
| | | import org.opends.server.types.DirectoryException; |
| | | import org.opends.server.types.RawFilter; |
| | | import org.opends.server.core.DirectoryServer; |
| | | import org.testng.annotations.DataProvider; |
| | | import org.testng.annotations.Test; |
| | | import org.testng.annotations.BeforeClass; |
| | | import org.testng.Assert; |
| | | |
| | | import java.util.List; |
| | | import java.text.ParseException; |
| | | import java.util.ArrayList; |
| | | import java.util.Collections; |
| | | import java.util.LinkedHashSet; |
| | | import java.text.ParseException; |
| | | import java.util.List; |
| | | |
| | | import static java.util.Arrays.asList; |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | | import org.opends.server.DirectoryServerTestCase; |
| | | import org.opends.server.TestCaseUtils; |
| | | import org.opends.server.core.DirectoryServer; |
| | | import org.opends.server.util.Base64; |
| | | import org.opends.server.util.StaticUtils; |
| | | import org.testng.Assert; |
| | | import org.testng.annotations.BeforeClass; |
| | | import org.testng.annotations.DataProvider; |
| | | import org.testng.annotations.Test; |
| | | |
| | | import static java.util.Arrays.*; |
| | | |
| | | import static org.opends.server.util.StaticUtils.*; |
| | | import static org.testng.Assert.*; |
| | | |
| | |
| | | private FilterDescription assertionFilterDescription(FilterType filterType, |
| | | String attributeType, |
| | | String attributeValue, |
| | | List<String> matchedEntries) { |
| | | String... matchedEntries) { |
| | | FilterDescription description = new FilterDescription(); |
| | | |
| | | description.filterType = filterType; |
| | |
| | | fail(filterType + " is not handled."); |
| | | } |
| | | |
| | | description.matchedEntriesLdif = matchedEntries; |
| | | description.unmatchedEntriesLdif = getEntriesExcluding(matchedEntries); |
| | | description.matchedEntriesLdif = asList(matchedEntries); |
| | | description.unmatchedEntriesLdif = getEntriesExcluding(description.matchedEntriesLdif); |
| | | |
| | | return description; |
| | | } |
| | |
| | | |
| | | private FilterDescription equalityFilterDescription(String attributeType, |
| | | String attributeValue, |
| | | List<String> matchedEntries) { |
| | | String... matchedEntries) { |
| | | return assertionFilterDescription(FilterType.EQUALITY, attributeType, attributeValue, matchedEntries); |
| | | } |
| | | |
| | | |
| | | private FilterDescription lessEqualFilterDescription(String attributeType, |
| | | String attributeValue, |
| | | List<String> matchedEntries) { |
| | | String... matchedEntries) { |
| | | return assertionFilterDescription(FilterType.LESS_OR_EQUAL, attributeType, attributeValue, matchedEntries); |
| | | } |
| | | |
| | | |
| | | private FilterDescription greaterEqualFilterDescription(String attributeType, |
| | | String attributeValue, |
| | | List<String> matchedEntries) { |
| | | String... matchedEntries) { |
| | | return assertionFilterDescription(FilterType.GREATER_OR_EQUAL, attributeType, attributeValue, matchedEntries); |
| | | } |
| | | |
| | | |
| | | private FilterDescription approximateFilterDescription(String attributeType, |
| | | String attributeValue, |
| | | List<String> matchedEntries) { |
| | | String... matchedEntries) { |
| | | return assertionFilterDescription(FilterType.APPROXIMATE_MATCH, attributeType, attributeValue, matchedEntries); |
| | | } |
| | | |
| | |
| | | |
| | | description.subInitialElement = ByteString.valueOf(subInitial); |
| | | description.subAnyElements = new ArrayList<ByteString>(); |
| | | for (int i = 0; (subAny != null) && (i < subAny.size()); i++) { |
| | | String s = subAny.get(i); |
| | | description.subAnyElements.add(ByteString.valueOf(s)); |
| | | if (subAny != null) |
| | | { |
| | | for (String s : subAny) |
| | | { |
| | | description.subAnyElements.add(ByteString.valueOf(s)); |
| | | } |
| | | } |
| | | description.subFinalElement = ByteString.valueOf(subFinal); |
| | | |
| | |
| | | |
| | | |
| | | private List<FilterDescription> getEqualityFilters() throws Exception { |
| | | List<FilterDescription> descriptions = new ArrayList<FilterDescription>(); |
| | | |
| | | descriptions.add(equalityFilterDescription("sn", "Smith", |
| | | asList(JANE_SMITH_LDIF, JOE_SMITH_LDIF))); |
| | | |
| | | descriptions.add(equalityFilterDescription("givenname", "Jane", |
| | | asList(JANE_SMITH_LDIF, JANE_AUSTIN_LDIF))); |
| | | |
| | | return descriptions; |
| | | return asList( |
| | | equalityFilterDescription("sn", "Smith", JANE_SMITH_LDIF, JOE_SMITH_LDIF), |
| | | equalityFilterDescription("givenname", "Jane", JANE_SMITH_LDIF, JANE_AUSTIN_LDIF)); |
| | | } |
| | | |
| | | |
| | | private List<FilterDescription> getApproximateFilters() throws Exception { |
| | | List<FilterDescription> descriptions = new ArrayList<FilterDescription>(); |
| | | |
| | | descriptions.add(approximateFilterDescription("sn", "Smythe", |
| | | asList(JANE_SMITH_LDIF, JOE_SMITH_LDIF))); |
| | | |
| | | return descriptions; |
| | | return asList(approximateFilterDescription("sn", "Smythe", JANE_SMITH_LDIF, JOE_SMITH_LDIF)); |
| | | } |
| | | |
| | | |
| | | private List<FilterDescription> getSubstringFilters() throws Exception { |
| | | List<FilterDescription> descriptions = new ArrayList<FilterDescription>(); |
| | | |
| | | descriptions.add(substringFilterDescription( |
| | | return asList(substringFilterDescription( |
| | | "sn", |
| | | "S", asList("i"), "th", // S*i*th |
| | | asList(JANE_SMITH_LDIF, JOE_SMITH_LDIF))); |
| | | |
| | | return descriptions; |
| | | } |
| | | |
| | | |
| | | private List<FilterDescription> getInequalityFilters() throws Exception { |
| | | List<FilterDescription> descriptions = new ArrayList<FilterDescription>(); |
| | | |
| | | descriptions.add(lessEqualFilterDescription("sn", "Aus", |
| | | new ArrayList<String>())); |
| | | |
| | | descriptions.add(greaterEqualFilterDescription("sn", "Aus", |
| | | asList(JANE_AUSTIN_LDIF, JOE_AUSTIN_LDIF, |
| | | JANE_SMITH_LDIF, JOE_SMITH_LDIF))); |
| | | |
| | | |
| | | descriptions.add(lessEqualFilterDescription("sn", "Smi", |
| | | asList(JANE_AUSTIN_LDIF, JOE_AUSTIN_LDIF))); |
| | | |
| | | descriptions.add(greaterEqualFilterDescription("sn", "Smi", |
| | | asList(JANE_SMITH_LDIF, JOE_SMITH_LDIF))); |
| | | |
| | | |
| | | descriptions.add(lessEqualFilterDescription("sn", "Smith", |
| | | asList(JANE_AUSTIN_LDIF, JOE_AUSTIN_LDIF, |
| | | JANE_SMITH_LDIF, JOE_SMITH_LDIF))); |
| | | |
| | | descriptions.add(greaterEqualFilterDescription("sn", "Smith", |
| | | asList(JANE_SMITH_LDIF, JOE_SMITH_LDIF))); |
| | | |
| | | |
| | | return descriptions; |
| | | return asList( |
| | | lessEqualFilterDescription("sn", "Aus"), |
| | | greaterEqualFilterDescription("sn", "Aus", |
| | | JANE_AUSTIN_LDIF, JOE_AUSTIN_LDIF, JANE_SMITH_LDIF, JOE_SMITH_LDIF), |
| | | lessEqualFilterDescription("sn", "Smi", |
| | | JANE_AUSTIN_LDIF, JOE_AUSTIN_LDIF), |
| | | greaterEqualFilterDescription("sn", "Smi", |
| | | JANE_SMITH_LDIF, JOE_SMITH_LDIF), |
| | | lessEqualFilterDescription("sn", "Smith", |
| | | JANE_AUSTIN_LDIF, JOE_AUSTIN_LDIF, JANE_SMITH_LDIF, JOE_SMITH_LDIF), |
| | | greaterEqualFilterDescription("sn", "Smith", |
| | | JANE_SMITH_LDIF, JOE_SMITH_LDIF)); |
| | | } |
| | | |
| | | |
| | |
| | | // Now convert to [][] |
| | | FilterDescription[][] descriptionArray = new FilterDescription[allDescriptions.size()][]; |
| | | for (int i = 0; i < allDescriptions.size(); i++) { |
| | | FilterDescription description = allDescriptions.get(i); |
| | | descriptionArray[i] = new FilterDescription[]{description}; |
| | | descriptionArray[i] = new FilterDescription[]{ allDescriptions.get(i) }; |
| | | } |
| | | |
| | | return descriptionArray; |
| | |
| | | |
| | | for (String ldif: description.matchedEntriesLdif) { |
| | | Entry entry = TestCaseUtils.entryFromLdifString(ldif); |
| | | if (!description.searchFilter.matchesEntry(entry)) { |
| | | fail("Expected to match entry. " + description + entry); |
| | | } |
| | | assertTrue(description.searchFilter.matchesEntry(entry), |
| | | "Expected to match entry. " + description + " " + entry); |
| | | } |
| | | |
| | | for (String ldif: description.unmatchedEntriesLdif) { |
| | | Entry entry = TestCaseUtils.entryFromLdifString(ldif); |
| | | if (description.searchFilter.matchesEntry(entry)) { |
| | | fail("Should not have matched entry. " + description + entry); |
| | | } |
| | | assertFalse(description.searchFilter.matchesEntry(entry), |
| | | "Should not have matched entry. " + description + " " + entry); |
| | | } |
| | | } |
| | | |
| | |
| | | @DataProvider(name = "differentNormalization") |
| | | public Object[][] differentNormalizationData() throws ParseException |
| | | { |
| | | final String BASE64_CERT_VALUE = |
| | | final String BASE64_CERT_VALUE = |
| | | "MIICpTCCAg6gAwIBAgIJALeoA6I3ZC/cMA0GCSqGSIb3DQEBBQUAMFYxCzAJBgNV" + |
| | | "BAYTAlVTMRMwEQYDVQQHEwpDdXBlcnRpb25lMRwwGgYDVQQLExNQcm9kdWN0IERl" + |
| | | "dmVsb3BtZW50MRQwEgYDVQQDEwtCYWJzIEplbnNlbjAeFw0xMjA1MDIxNjM0MzVa" + |
| | |
| | | "6CD0WRmc2pBeYX2z94/PWO5L3Fx+eIZh2wTxScF+FdRWJzLbUaBuClrxuy0Y5ifj" + |
| | | "axuJ8LFNbZtsp1ldW3i84+F5+SYT+xI67ZcoAtwx/VFVI9s5I/Gkmu9f9nxjPpK7" + |
| | | "1AIUXiE3Qcck"; |
| | | final String CERT_EXACT_ASSERTION = |
| | | final String CERT_EXACT_ASSERTION = |
| | | "{ serialNumber 13233831500277100508, issuer rdnSequence:\""+ |
| | | "CN=Babs Jensen,OU=Product Development,L=Cupertione,C=US\" }"; |
| | | final String CERTIFICATE_LDIF = TestCaseUtils.makeLdif( |
| | | final String LDIF_ENTRY = TestCaseUtils.makeLdif( |
| | | "dn: cn=John Smith,dc=example,dc=com", |
| | | "objectclass: inetorgperson", |
| | | "cn: John Smith", |
| | |
| | | final String CERTIFICATE_ENCODED = builder.toString(); |
| | | |
| | | return new Object[][]{ |
| | | {CERTIFICATE_LDIF, "userCertificate="+CERT_EXACT_ASSERTION, true}, |
| | | {CERTIFICATE_LDIF, "userCertificate="+CERTIFICATE_ENCODED, true}}; |
| | | { LDIF_ENTRY, "userCertificate=" + CERT_EXACT_ASSERTION, true }, |
| | | { LDIF_ENTRY, "userCertificate=" + CERTIFICATE_ENCODED, true }, |
| | | }; |
| | | } |
| | | |
| | | @Test(dataProvider = "differentNormalization") |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt |
| | | * or http://forgerock.org/license/CDDLv1.0.html. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at legal-notices/CDDLv1_0.txt. |
| | | * If applicable, add the following below this CDDL HEADER, with the |
| | | * fields enclosed by brackets "[]" replaced with your own identifying |
| | | * information: |
| | | * Portions Copyright [yyyy] [name of copyright owner] |
| | | * |
| | | * CDDL HEADER END |
| | | * |
| | | * Copyright 2014 ForgeRock AS |
| | | */ |
| | | package org.opends.server.types; |
| | | |
| | | import java.util.*; |
| | | import java.util.Map.Entry; |
| | | |
| | | import org.testng.annotations.Test; |
| | | |
| | | import static org.assertj.core.api.Assertions.*; |
| | | import static org.testng.Assert.*; |
| | | |
| | | @SuppressWarnings("javadoc") |
| | | public class SmallMapTest |
| | | { |
| | | |
| | | @Test |
| | | public void testPutAndSize() throws Exception |
| | | { |
| | | SmallMap<Integer, String> map = new SmallMap<Integer, String>(); |
| | | assertEquals(map.size(), 0); |
| | | assertEquals(map.put(1, "one"), null); |
| | | assertEquals(map.size(), 1); |
| | | assertEquals(map.put(1, "ONE"), "one"); |
| | | assertEquals(map.size(), 1); |
| | | assertEquals(map.put(2, "two"), null); |
| | | assertEquals(map.size(), 2); |
| | | assertEquals(map.put(3, "three"), null); |
| | | assertEquals(map.size(), 3); |
| | | } |
| | | |
| | | @Test(dependsOnMethods = { "testPutAndSize" }) |
| | | public void testGet() throws Exception |
| | | { |
| | | SmallMap<Integer, String> map = new SmallMap<Integer, String>(); |
| | | assertEquals(map.get(1), null); |
| | | assertEquals(map.get(2), null); |
| | | map.put(1, "one"); |
| | | assertEquals(map.get(1), "one"); |
| | | assertEquals(map.get(2), null); |
| | | map.put(1, "ONE"); |
| | | assertEquals(map.get(1), "ONE"); |
| | | assertEquals(map.get(2), null); |
| | | map.put(2, "two"); |
| | | assertEquals(map.get(1), "ONE"); |
| | | assertEquals(map.get(2), "two"); |
| | | } |
| | | |
| | | @Test(dependsOnMethods = { "testPutAndSize" }) |
| | | public void testPutAll() throws Exception |
| | | { |
| | | final SmallMap<Integer, String> map = new SmallMap<Integer, String>(); |
| | | final HashMap<Integer, String> hashMap = new HashMap<Integer, String>(); |
| | | map.putAll(hashMap); |
| | | assertEquals(map.size(), 0); |
| | | hashMap.put(1, "one"); |
| | | map.putAll(hashMap); |
| | | assertEquals(map.size(), 1); |
| | | assertEquals(map.get(1), "one"); |
| | | } |
| | | |
| | | @Test(dependsOnMethods = { "testPutAndSize" }) |
| | | public void testRemove() throws Exception |
| | | { |
| | | SmallMap<Integer, String> map = new SmallMap<Integer, String>(); |
| | | assertEquals(map.size(), 0); |
| | | assertEquals(map.remove(2), null); |
| | | assertEquals(map.remove(1), null); |
| | | |
| | | map.put(1, "one"); |
| | | assertEquals(map.size(), 1); |
| | | assertEquals(map.remove(2), null); |
| | | assertEquals(map.remove(1), "one"); |
| | | assertEquals(map.size(), 0); |
| | | |
| | | map.put(1, "one"); |
| | | map.put(2, "two"); |
| | | assertEquals(map.size(), 2); |
| | | assertEquals(map.remove(1), "one"); |
| | | assertEquals(map.size(), 1); |
| | | } |
| | | |
| | | @Test(dependsOnMethods = { "testPutAndSize" }) |
| | | public void testContains() throws Exception |
| | | { |
| | | SmallMap<Integer, String> map = new SmallMap<Integer, String>(); |
| | | assertDoesNotContain(map, entry(2, "two")); |
| | | |
| | | map.put(1, null); |
| | | assertContains(map, entry(1, (String) null)); |
| | | assertDoesNotContain(map, entry(2, "two")); |
| | | |
| | | map.put(1, "one"); |
| | | assertContains(map, entry(1, "one")); |
| | | assertDoesNotContain(map, entry(2, "two")); |
| | | |
| | | map.put(2, "two"); |
| | | assertContains(map, entry(1, "one")); |
| | | assertContains(map, entry(2, "two")); |
| | | assertDoesNotContain(map, entry(3, "three")); |
| | | } |
| | | |
| | | @Test(dependsOnMethods = { "testPutAndSize" }) |
| | | public void testClear() throws Exception |
| | | { |
| | | SmallMap<Integer, String> map = new SmallMap<Integer, String>(); |
| | | map.clear(); |
| | | assertEquals(map.size(), 0); |
| | | |
| | | map.put(1, "one"); |
| | | map.clear(); |
| | | assertEquals(map.size(), 0); |
| | | |
| | | map.put(1, "one"); |
| | | map.put(2, "two"); |
| | | map.clear(); |
| | | assertEquals(map.size(), 0); |
| | | } |
| | | |
| | | @Test(dependsOnMethods = { "testPutAndSize" }) |
| | | public void testEntrySetSize() throws Exception |
| | | { |
| | | SmallMap<Integer, String> map = new SmallMap<Integer, String>(); |
| | | assertEquals(map.entrySet().size(), 0); |
| | | |
| | | map.put(1, "one"); |
| | | assertEquals(map.entrySet().size(), 1); |
| | | |
| | | map.put(1, "one"); |
| | | map.put(2, "two"); |
| | | assertEquals(map.entrySet().size(), 2); |
| | | } |
| | | |
| | | @SuppressWarnings("unchecked") |
| | | @Test(dependsOnMethods = { "testEntrySetSize" }) |
| | | public void testEntrySetIterator() throws Exception |
| | | { |
| | | SmallMap<Integer, String> map = new SmallMap<Integer, String>(); |
| | | assertThat(map.entrySet().iterator()).isEmpty(); |
| | | |
| | | map.put(1, "one"); |
| | | assertThat(map.entrySet().iterator()).containsExactly( |
| | | entry(1, "one")); |
| | | |
| | | map.put(1, "one"); |
| | | map.put(2, "two"); |
| | | assertThat(map.entrySet().iterator()).containsExactly( |
| | | entry(1, "one"), entry(2, "two")); |
| | | } |
| | | |
| | | @Test(dependsOnMethods = { "testEntrySetIterator" }) |
| | | public void testEntrySetIteratorNextRemove() throws Exception |
| | | { |
| | | SmallMap<Integer, String> map = new SmallMap<Integer, String>(); |
| | | map.put(1, "one"); |
| | | Iterator<Entry<Integer, String>> iter = map.entrySet().iterator(); |
| | | assertTrue(iter.hasNext()); |
| | | assertNotNull(iter.next()); |
| | | iter.remove(); |
| | | assertFalse(iter.hasNext()); |
| | | |
| | | assertTrue(map.isEmpty()); |
| | | } |
| | | |
| | | @Test(dependsOnMethods = { "testEntrySetIterator" }, |
| | | expectedExceptions = { NoSuchElementException.class }) |
| | | public void testEntrySetIteratorNextThrowsNoSuchElementException() throws Exception |
| | | { |
| | | SmallMap<Integer, String> map = new SmallMap<Integer, String>(); |
| | | map.put(1, "one"); |
| | | Iterator<Entry<Integer, String>> iter = map.entrySet().iterator(); |
| | | assertTrue(iter.hasNext()); |
| | | iter.next(); |
| | | assertFalse(iter.hasNext()); |
| | | iter.next(); // throw an exception |
| | | } |
| | | |
| | | private <K, V> Entry<K, V> entry(K key, V value) |
| | | { |
| | | return new AbstractMap.SimpleImmutableEntry<K, V>(key, value); |
| | | } |
| | | |
| | | private void assertContains(SmallMap<Integer, String> map, |
| | | Entry<Integer, String> entry) |
| | | { |
| | | assertContains(map, entry, true); |
| | | } |
| | | |
| | | private void assertDoesNotContain(SmallMap<Integer, String> map, |
| | | Entry<Integer, String> entry) |
| | | { |
| | | assertContains(map, entry, false); |
| | | } |
| | | |
| | | private void assertContains(SmallMap<Integer, String> map, |
| | | Entry<Integer, String> entry, boolean expected) |
| | | { |
| | | assertEquals(map.containsKey(entry.getKey()), expected); |
| | | assertEquals(map.containsValue(entry.getValue()), expected); |
| | | } |
| | | |
| | | @Test(expectedExceptions = { NullPointerException.class }) |
| | | public void testGetRejectsNull() throws Exception |
| | | { |
| | | new SmallMap<Integer, String>().get(null); |
| | | } |
| | | |
| | | @Test(expectedExceptions = { NullPointerException.class }) |
| | | public void testContainsKeyRejectsNull() throws Exception |
| | | { |
| | | new SmallMap<Integer, String>().containsKey(null); |
| | | } |
| | | |
| | | @Test(expectedExceptions = { NullPointerException.class }) |
| | | public void testPutRejectsNull() throws Exception |
| | | { |
| | | new SmallMap<Integer, String>().put(null, null); |
| | | } |
| | | |
| | | @Test(expectedExceptions = { NullPointerException.class }) |
| | | public void testPutAllRejectsNull() throws Exception |
| | | { |
| | | final HashMap<Integer, String> map = new HashMap<Integer, String>(); |
| | | map.put(null, null); |
| | | new SmallMap<Integer, String>().putAll(map); |
| | | } |
| | | } |
| | |
| | | Entry entry = createTestEntry(type, values); |
| | | Set<SubtreeSpecification> result = new HashSet<SubtreeSpecification>(); |
| | | List<Attribute> attributes = entry.getAttribute(type, true); |
| | | for (ByteString value : new AttributeValueIterable(attributes)) |
| | | for (Attribute a : attributes) |
| | | { |
| | | result.add(SubtreeSpecification.valueOf(rootDN, value.toString())); |
| | | for (ByteString value : a) |
| | | { |
| | | result.add(SubtreeSpecification.valueOf(rootDN, value.toString())); |
| | | } |
| | | } |
| | | |
| | | assertEquals(expected, result); |
| | | } |
| | | |