OPENDJ-1864: Ordering matching rules should reuse equality indexes where possible
| | |
| | | <justification>OPENDJ-1689 method has been removed because all matching rules should support the default comparator</justification> |
| | | </difference> |
| | | <difference> |
| | | <className>org/forgerock/opendj/ldap/schema/MatchingRuleImpl</className> |
| | | <differenceType>7012</differenceType> |
| | | <method>java.util.Collection createIndexers(org.forgerock.opendj.ldap.spi.IndexingOptions)</method> |
| | | <justification>Doesn't really seem correct to call createKeys() with different options each time.</justification> |
| | | </difference> |
| | | <difference> |
| | | <className>org/forgerock/opendj/ldap/ByteSequence</className> |
| | | <differenceType>7012</differenceType> |
| | | <method>boolean startsWith(org.forgerock.opendj.ldap.ByteSequence)</method> |
| | |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright 2014 ForgeRock AS |
| | | * Copyright 2014-2015 ForgeRock AS |
| | | */ |
| | | package org.forgerock.opendj.ldap.schema; |
| | | |
| | |
| | | import org.forgerock.opendj.ldap.ByteSequence; |
| | | import org.forgerock.opendj.ldap.DecodeException; |
| | | import org.forgerock.opendj.ldap.spi.Indexer; |
| | | import org.forgerock.opendj.ldap.spi.IndexingOptions; |
| | | |
| | | /** |
| | | * This class implements an approximate matching rule that matches normalized |
| | |
| | | */ |
| | | abstract class AbstractApproximateMatchingRuleImpl extends AbstractMatchingRuleImpl { |
| | | |
| | | private final Collection<? extends Indexer> indexers = |
| | | Collections.singleton(new DefaultIndexer("approximate")); |
| | | private final Indexer indexer; |
| | | |
| | | AbstractApproximateMatchingRuleImpl() { |
| | | // Nothing to do. |
| | | AbstractApproximateMatchingRuleImpl(String indexID) { |
| | | indexer = new DefaultIndexer(indexID); |
| | | } |
| | | |
| | | @Override |
| | | public Assertion getAssertion(final Schema schema, final ByteSequence assertionValue) |
| | | public final Assertion getAssertion(final Schema schema, final ByteSequence assertionValue) |
| | | throws DecodeException { |
| | | return DefaultAssertion.approximate(normalizeAttributeValue(schema, assertionValue)); |
| | | return named(indexer.getIndexID(), normalizeAttributeValue(schema, assertionValue)); |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public Collection<? extends Indexer> getIndexers() { |
| | | return indexers; |
| | | public final Collection<? extends Indexer> createIndexers(IndexingOptions options) { |
| | | return Collections.singleton(indexer); |
| | | } |
| | | } |
| | |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright 2014 ForgeRock AS |
| | | * Copyright 2014-2015 ForgeRock AS |
| | | */ |
| | | package org.forgerock.opendj.ldap.schema; |
| | | |
| | |
| | | import org.forgerock.opendj.ldap.ByteSequence; |
| | | import org.forgerock.opendj.ldap.DecodeException; |
| | | import org.forgerock.opendj.ldap.spi.Indexer; |
| | | import org.forgerock.opendj.ldap.spi.IndexingOptions; |
| | | |
| | | /** |
| | | * This class implements an equality matching rule that matches normalized |
| | |
| | | */ |
| | | abstract class AbstractEqualityMatchingRuleImpl extends AbstractMatchingRuleImpl { |
| | | |
| | | private final Collection<? extends Indexer> indexers = Collections.singleton(new DefaultIndexer("equality")); |
| | | private final Indexer indexer; |
| | | |
| | | AbstractEqualityMatchingRuleImpl() { |
| | | // Nothing to do. |
| | | AbstractEqualityMatchingRuleImpl(String indexID) { |
| | | this.indexer = new DefaultIndexer(indexID); |
| | | } |
| | | |
| | | @Override |
| | | public Assertion getAssertion(final Schema schema, final ByteSequence assertionValue) |
| | | throws DecodeException { |
| | | return DefaultAssertion.equality(normalizeAttributeValue(schema, assertionValue)); |
| | | return defaultAssertion(normalizeAttributeValue(schema, assertionValue)); |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public Collection<? extends Indexer> getIndexers() { |
| | | return indexers; |
| | | public Collection<? extends Indexer> createIndexers(IndexingOptions options) { |
| | | return Collections.singleton(indexer); |
| | | } |
| | | |
| | | Assertion defaultAssertion(final ByteSequence normalizedAssertionValue) { |
| | | return named(indexer.getIndexID(), normalizedAssertionValue); |
| | | } |
| | | |
| | | } |
| | |
| | | import org.forgerock.opendj.ldap.DecodeException; |
| | | import org.forgerock.opendj.ldap.spi.IndexQueryFactory; |
| | | import org.forgerock.opendj.ldap.spi.Indexer; |
| | | import org.forgerock.opendj.ldap.spi.IndexingOptions; |
| | | |
| | | import static org.forgerock.opendj.ldap.Assertion.*; |
| | | |
| | |
| | | */ |
| | | abstract class AbstractMatchingRuleImpl implements MatchingRuleImpl { |
| | | |
| | | static final class DefaultAssertion implements Assertion { |
| | | static DefaultAssertion named(final String indexID, final ByteSequence normalizedAssertionValue) { |
| | | return new DefaultAssertion(indexID, normalizedAssertionValue); |
| | | } |
| | | |
| | | private static final class DefaultAssertion implements Assertion { |
| | | /** The ID of the DB index to use with this assertion.*/ |
| | | private final String indexID; |
| | | private final ByteSequence normalizedAssertionValue; |
| | | |
| | | static DefaultAssertion equality(final ByteSequence normalizedAssertionValue) { |
| | | return named("equality", normalizedAssertionValue); |
| | | } |
| | | |
| | | static DefaultAssertion approximate(final ByteSequence normalizedAssertionValue) { |
| | | return named("approximate", normalizedAssertionValue); |
| | | } |
| | | |
| | | static DefaultAssertion named(final String indexID, final ByteSequence normalizedAssertionValue) { |
| | | return new DefaultAssertion(indexID, normalizedAssertionValue); |
| | | } |
| | | |
| | | private DefaultAssertion(final String indexID, final ByteSequence normalizedAssertionValue) { |
| | | this.indexID = indexID; |
| | | this.normalizedAssertionValue = normalizedAssertionValue; |
| | |
| | | } |
| | | |
| | | @Override |
| | | public void createKeys(Schema schema, ByteSequence value, IndexingOptions options, Collection<ByteString> keys) |
| | | throws DecodeException { |
| | | public void createKeys(Schema schema, ByteSequence value, Collection<ByteString> keys) throws DecodeException { |
| | | keys.add(normalizeAttributeValue(schema, value)); |
| | | } |
| | | |
| | |
| | | } |
| | | } |
| | | |
| | | AbstractMatchingRuleImpl() { |
| | | // Nothing to do. |
| | | } |
| | | |
| | | @Override |
| | | public Assertion getAssertion(final Schema schema, final ByteSequence assertionValue) |
| | | throws DecodeException { |
| | |
| | | throws DecodeException { |
| | | return UNDEFINED_ASSERTION; |
| | | } |
| | | |
| | | @Override |
| | | public boolean isIndexingSupported() { |
| | | return !getIndexers().isEmpty(); |
| | | } |
| | | |
| | | } |
| | |
| | | * |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Portions copyright 2014 ForgeRock AS |
| | | * Portions copyright 2014-2015 ForgeRock AS |
| | | */ |
| | | package org.forgerock.opendj.ldap.schema; |
| | | |
| | |
| | | import org.forgerock.opendj.ldap.DecodeException; |
| | | import org.forgerock.opendj.ldap.spi.IndexQueryFactory; |
| | | import org.forgerock.opendj.ldap.spi.Indexer; |
| | | import org.forgerock.opendj.ldap.spi.IndexingOptions; |
| | | |
| | | /** |
| | | * This class implements a default ordering matching rule that matches |
| | |
| | | * this assumption does not hold true. |
| | | */ |
| | | abstract class AbstractOrderingMatchingRuleImpl extends AbstractMatchingRuleImpl { |
| | | private final Collection<? extends Indexer> indexers; |
| | | private final String indexId; |
| | | |
| | | /** Constructor for default matching rules. */ |
| | | AbstractOrderingMatchingRuleImpl() { |
| | | this("ordering"); |
| | | } |
| | | private final Indexer indexer; |
| | | |
| | | /** Constructor for non-default matching rules. */ |
| | | AbstractOrderingMatchingRuleImpl(String indexId) { |
| | | this.indexId = indexId; |
| | | this.indexers = Collections.singleton(new DefaultIndexer(indexId)); |
| | | this.indexer = new DefaultIndexer(indexId); |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public Assertion getAssertion(final Schema schema, final ByteSequence value) |
| | | public final Assertion getAssertion(final Schema schema, final ByteSequence value) |
| | | throws DecodeException { |
| | | final ByteString normAssertion = normalizeAttributeValue(schema, value); |
| | | return new Assertion() { |
| | |
| | | |
| | | @Override |
| | | public <T> T createIndexQuery(IndexQueryFactory<T> factory) throws DecodeException { |
| | | return factory.createRangeMatchQuery(indexId, ByteString.empty(), normAssertion, false, false); |
| | | return factory.createRangeMatchQuery(indexer.getIndexID(), ByteString.empty(), normAssertion, false, |
| | | false); |
| | | } |
| | | }; |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public Assertion getGreaterOrEqualAssertion(final Schema schema, final ByteSequence value) throws DecodeException { |
| | | public final Assertion getGreaterOrEqualAssertion(final Schema schema, final ByteSequence value) |
| | | throws DecodeException { |
| | | final ByteString normAssertion = normalizeAttributeValue(schema, value); |
| | | return new Assertion() { |
| | | @Override |
| | |
| | | |
| | | @Override |
| | | public <T> T createIndexQuery(IndexQueryFactory<T> factory) throws DecodeException { |
| | | return factory.createRangeMatchQuery(indexId, normAssertion, ByteString.empty(), true, false); |
| | | return factory.createRangeMatchQuery(indexer.getIndexID(), normAssertion, ByteString.empty(), true, |
| | | false); |
| | | } |
| | | }; |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public Assertion getLessOrEqualAssertion(final Schema schema, final ByteSequence value) |
| | | public final Assertion getLessOrEqualAssertion(final Schema schema, final ByteSequence value) |
| | | throws DecodeException { |
| | | final ByteString normAssertion = normalizeAttributeValue(schema, value); |
| | | return new Assertion() { |
| | |
| | | |
| | | @Override |
| | | public <T> T createIndexQuery(IndexQueryFactory<T> factory) throws DecodeException { |
| | | return factory.createRangeMatchQuery(indexId, ByteString.empty(), normAssertion, false, true); |
| | | return factory.createRangeMatchQuery(indexer.getIndexID(), ByteString.empty(), normAssertion, false, |
| | | true); |
| | | } |
| | | }; |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public Collection<? extends Indexer> getIndexers() { |
| | | return indexers; |
| | | public final Collection<? extends Indexer> createIndexers(IndexingOptions options) { |
| | | return Collections.singleton(indexer); |
| | | } |
| | | |
| | | final String getIndexId() { |
| | | return indexId; |
| | | } |
| | | } |
| | |
| | | |
| | | } |
| | | |
| | | final class SubstringIndexer implements Indexer { |
| | | private final class SubstringIndexer implements Indexer { |
| | | |
| | | private final String indexID; |
| | | private final int substringKeySize; |
| | | |
| | | private SubstringIndexer(int substringKeySize) { |
| | | this.substringKeySize = substringKeySize; |
| | | this.indexID = substringIndexId + ":" + this.substringKeySize; |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public void createKeys(Schema schema, ByteSequence value, IndexingOptions options, Collection<ByteString> keys) |
| | | throws DecodeException { |
| | | public void createKeys(Schema schema, ByteSequence value, Collection<ByteString> keys) throws DecodeException { |
| | | final ByteString normValue = normalizeAttributeValue(schema, value); |
| | | final int substringKeySize = options.substringKeySize(); |
| | | |
| | | // Example: The value is ABCDE and the substring length is 3. |
| | | // We produce the keys ABC BCD CDE DE E |
| | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public String getIndexID() { |
| | | return substringIndexId; |
| | | return indexID; |
| | | } |
| | | } |
| | | |
| | | private final Collection<? extends Indexer> indexers = Collections.singleton(new SubstringIndexer()); |
| | | |
| | | /** Identifier of the substring index. */ |
| | | private final String substringIndexId; |
| | | |
| | | /** Identifier of the equality index. */ |
| | | private final String equalityIndexId; |
| | | |
| | | /** Constructor for default matching rules. */ |
| | | AbstractSubstringMatchingRuleImpl() { |
| | | this("substring", "equality"); |
| | | } |
| | | |
| | | /** Constructor for non-default matching rules. */ |
| | | AbstractSubstringMatchingRuleImpl(String substringIndexId, String equalityIndexId) { |
| | | this.substringIndexId = substringIndexId; |
| | |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public Assertion getAssertion(final Schema schema, final ByteSequence assertionValue) |
| | | public final Assertion getAssertion(final Schema schema, final ByteSequence assertionValue) |
| | | throws DecodeException { |
| | | if (assertionValue.length() == 0) { |
| | | throw DecodeException.error(WARN_ATTR_SYNTAX_SUBSTRING_EMPTY.get()); |
| | |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public Assertion getSubstringAssertion(final Schema schema, final ByteSequence subInitial, |
| | | public final Assertion getSubstringAssertion(final Schema schema, final ByteSequence subInitial, |
| | | final List<? extends ByteSequence> subAnyElements, final ByteSequence subFinal) |
| | | throws DecodeException { |
| | | final ByteString normInitial = |
| | |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public Collection<? extends Indexer> getIndexers() { |
| | | return indexers; |
| | | public final Collection<? extends Indexer> createIndexers(IndexingOptions options) { |
| | | return Collections.singleton(new SubstringIndexer(options.substringKeySize())); |
| | | } |
| | | |
| | | } |
| | |
| | | * |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Portions copyright 2014 ForgeRock AS |
| | | * Portions copyright 2014-2015 ForgeRock AS |
| | | */ |
| | | package org.forgerock.opendj.ldap.schema; |
| | | |
| | | import static org.forgerock.opendj.ldap.schema.SchemaConstants.*; |
| | | |
| | | import org.forgerock.opendj.ldap.ByteSequence; |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | | import org.forgerock.opendj.ldap.DecodeException; |
| | |
| | | * 3112. |
| | | */ |
| | | final class AuthPasswordExactEqualityMatchingRuleImpl extends AbstractEqualityMatchingRuleImpl { |
| | | |
| | | AuthPasswordExactEqualityMatchingRuleImpl() { |
| | | super(EMR_AUTH_PASSWORD_EXACT_NAME); |
| | | } |
| | | |
| | | @Override |
| | | public ByteString normalizeAttributeValue(final Schema schema, final ByteSequence value) |
| | | throws DecodeException { |
| | | final StringBuilder[] authPWComponents = |
| | |
| | | * |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Portions copyright 2014 ForgeRock AS |
| | | * Portions copyright 2014-2015 ForgeRock AS |
| | | */ |
| | | package org.forgerock.opendj.ldap.schema; |
| | | |
| | | import static com.forgerock.opendj.ldap.CoreMessages.WARN_ATTR_SYNTAX_BIT_STRING_INVALID_BIT; |
| | | import static com.forgerock.opendj.ldap.CoreMessages.WARN_ATTR_SYNTAX_BIT_STRING_NOT_QUOTED; |
| | | import static com.forgerock.opendj.ldap.CoreMessages.WARN_ATTR_SYNTAX_BIT_STRING_TOO_SHORT; |
| | | import static org.forgerock.opendj.ldap.schema.SchemaConstants.*; |
| | | |
| | | import org.forgerock.i18n.LocalizableMessage; |
| | | import org.forgerock.opendj.ldap.ByteSequence; |
| | |
| | | * referenced in RFC 2252. |
| | | */ |
| | | final class BitStringEqualityMatchingRuleImpl extends AbstractEqualityMatchingRuleImpl { |
| | | |
| | | BitStringEqualityMatchingRuleImpl() { |
| | | super(EMR_BIT_STRING_NAME); |
| | | } |
| | | |
| | | @Override |
| | | public ByteString normalizeAttributeValue(final Schema schema, final ByteSequence value) |
| | | throws DecodeException { |
| | | final String valueString = value.toString().toUpperCase(); |
| | |
| | | * |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Portions copyright 2014 ForgeRock AS |
| | | * Portions copyright 2014-2015 ForgeRock AS |
| | | */ |
| | | package org.forgerock.opendj.ldap.schema; |
| | | |
| | | import static com.forgerock.opendj.ldap.CoreMessages.WARN_ATTR_SYNTAX_ILLEGAL_BOOLEAN; |
| | | import static org.forgerock.opendj.ldap.schema.SchemaConstants.*; |
| | | |
| | | import org.forgerock.opendj.ldap.ByteSequence; |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | |
| | | * referenced in RFC 4519. |
| | | */ |
| | | final class BooleanEqualityMatchingRuleImpl extends AbstractEqualityMatchingRuleImpl { |
| | | |
| | | BooleanEqualityMatchingRuleImpl() { |
| | | super(EMR_BOOLEAN_NAME); |
| | | } |
| | | |
| | | @Override |
| | | public ByteString normalizeAttributeValue(final Schema schema, final ByteSequence value) |
| | | throws DecodeException { |
| | | final String valueString = value.toString().toUpperCase(); |
| | |
| | | * |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Portions copyright 2014 ForgeRock AS |
| | | * Portions copyright 2014-2015 ForgeRock AS |
| | | */ |
| | | package org.forgerock.opendj.ldap.schema; |
| | | |
| | |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | | |
| | | import static com.forgerock.opendj.util.StringPrepProfile.*; |
| | | import static org.forgerock.opendj.ldap.schema.SchemaConstants.*; |
| | | |
| | | /** |
| | | * This class defines the caseExactMatch matching rule defined in X.520 and |
| | | * referenced in RFC 4519. |
| | | */ |
| | | final class CaseExactEqualityMatchingRuleImpl extends AbstractEqualityMatchingRuleImpl { |
| | | |
| | | CaseExactEqualityMatchingRuleImpl() { |
| | | super(EMR_CASE_EXACT_NAME); |
| | | } |
| | | |
| | | @Override |
| | | public ByteString normalizeAttributeValue(final Schema schema, final ByteSequence value) { |
| | | return SchemaUtils.normalizeStringAttributeValue(value, TRIM, NO_CASE_FOLD); |
| | |
| | | * |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Portions copyright 2014 ForgeRock AS |
| | | * Portions copyright 2014-2015 ForgeRock AS |
| | | */ |
| | | package org.forgerock.opendj.ldap.schema; |
| | | |
| | |
| | | import org.forgerock.opendj.ldap.DecodeException; |
| | | |
| | | import static com.forgerock.opendj.util.StringPrepProfile.*; |
| | | import static org.forgerock.opendj.ldap.schema.SchemaConstants.*; |
| | | |
| | | /** |
| | | * This class implements the caseExactIA5Match matching rule defined in RFC |
| | | * 2252. |
| | | */ |
| | | final class CaseExactIA5EqualityMatchingRuleImpl extends AbstractEqualityMatchingRuleImpl { |
| | | |
| | | CaseExactIA5EqualityMatchingRuleImpl() { |
| | | super(EMR_CASE_EXACT_IA5_NAME); |
| | | } |
| | | |
| | | @Override |
| | | public ByteString normalizeAttributeValue(final Schema schema, final ByteSequence value) |
| | | throws DecodeException { |
| | | return SchemaUtils.normalizeIA5StringAttributeValue(value, TRIM, NO_CASE_FOLD); |
| | |
| | | * |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Portions copyright 2014 ForgeRock AS |
| | | * Portions copyright 2014-2015 ForgeRock AS |
| | | */ |
| | | package org.forgerock.opendj.ldap.schema; |
| | | |
| | |
| | | import org.forgerock.opendj.ldap.DecodeException; |
| | | |
| | | import static com.forgerock.opendj.util.StringPrepProfile.*; |
| | | import static org.forgerock.opendj.ldap.schema.SchemaConstants.*; |
| | | |
| | | /** |
| | | * This class implements the caseExactIA5SubstringsMatch matching rule. This |
| | |
| | | * private namespace. |
| | | */ |
| | | final class CaseExactIA5SubstringMatchingRuleImpl extends AbstractSubstringMatchingRuleImpl { |
| | | |
| | | CaseExactIA5SubstringMatchingRuleImpl() { |
| | | super(SMR_CASE_EXACT_IA5_NAME, EMR_CASE_EXACT_IA5_NAME); |
| | | } |
| | | |
| | | @Override |
| | | public ByteString normalizeAttributeValue(final Schema schema, final ByteSequence value) |
| | | throws DecodeException { |
| | |
| | | * |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Portions copyright 2014 ForgeRock AS |
| | | * Portions copyright 2014-2015 ForgeRock AS |
| | | */ |
| | | package org.forgerock.opendj.ldap.schema; |
| | | |
| | |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | | |
| | | import static com.forgerock.opendj.util.StringPrepProfile.*; |
| | | import static org.forgerock.opendj.ldap.schema.SchemaConstants.*; |
| | | |
| | | /** |
| | | * This class defines the caseExactOrderingMatch matching rule defined in X.520 |
| | | * and referenced in RFC 4519. |
| | | */ |
| | | final class CaseExactOrderingMatchingRuleImpl extends AbstractOrderingMatchingRuleImpl { |
| | | |
| | | public CaseExactOrderingMatchingRuleImpl() { |
| | | // Reusing equality index since OPENDJ-1864 |
| | | super(EMR_CASE_EXACT_NAME); |
| | | } |
| | | |
| | | @Override |
| | | public ByteString normalizeAttributeValue(final Schema schema, final ByteSequence value) { |
| | | return SchemaUtils.normalizeStringAttributeValue(value, TRIM, NO_CASE_FOLD); |
| | | } |
| | |
| | | * |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Portions copyright 2014 ForgeRock AS |
| | | * Portions copyright 2014-2015 ForgeRock AS |
| | | */ |
| | | package org.forgerock.opendj.ldap.schema; |
| | | |
| | |
| | | import org.forgerock.opendj.ldap.DecodeException; |
| | | |
| | | import static com.forgerock.opendj.util.StringPrepProfile.*; |
| | | import static org.forgerock.opendj.ldap.schema.SchemaConstants.*; |
| | | |
| | | /** |
| | | * This class defines the caseExactSubstringsMatch matching rule defined in |
| | | * X.520 and referenced in RFC 2252. |
| | | */ |
| | | final class CaseExactSubstringMatchingRuleImpl extends AbstractSubstringMatchingRuleImpl { |
| | | |
| | | CaseExactSubstringMatchingRuleImpl() { |
| | | super(SMR_CASE_EXACT_NAME, EMR_CASE_EXACT_NAME); |
| | | } |
| | | |
| | | @Override |
| | | public ByteString normalizeAttributeValue(final Schema schema, final ByteSequence value) { |
| | | return normalize(TRIM, value); |
| | | } |
| | |
| | | * |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Portions copyright 2014 ForgeRock AS |
| | | * Portions copyright 2014-2015 ForgeRock AS |
| | | */ |
| | | package org.forgerock.opendj.ldap.schema; |
| | | |
| | | import static com.forgerock.opendj.util.StringPrepProfile.*; |
| | | import static org.forgerock.opendj.ldap.schema.SchemaConstants.*; |
| | | |
| | | import org.forgerock.opendj.ldap.ByteSequence; |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | |
| | | * referenced in RFC 2252. |
| | | */ |
| | | final class CaseIgnoreEqualityMatchingRuleImpl extends AbstractEqualityMatchingRuleImpl { |
| | | |
| | | CaseIgnoreEqualityMatchingRuleImpl() { |
| | | super(EMR_CASE_IGNORE_NAME); |
| | | } |
| | | |
| | | @Override |
| | | public ByteString normalizeAttributeValue(final Schema schema, final ByteSequence value) { |
| | | return SchemaUtils.normalizeStringAttributeValue(value, TRIM, CASE_FOLD); |
| | |
| | | * |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Portions copyright 2014 ForgeRock AS |
| | | * Portions copyright 2014-2015 ForgeRock AS |
| | | */ |
| | | package org.forgerock.opendj.ldap.schema; |
| | | |
| | |
| | | import org.forgerock.opendj.ldap.DecodeException; |
| | | |
| | | import static com.forgerock.opendj.util.StringPrepProfile.*; |
| | | import static org.forgerock.opendj.ldap.schema.SchemaConstants.*; |
| | | |
| | | /** |
| | | * This class implements the caseIgnoreIA5Match matching rule defined in RFC |
| | | * 2252. |
| | | */ |
| | | final class CaseIgnoreIA5EqualityMatchingRuleImpl extends AbstractEqualityMatchingRuleImpl { |
| | | |
| | | CaseIgnoreIA5EqualityMatchingRuleImpl() { |
| | | super(EMR_CASE_IGNORE_IA5_NAME); |
| | | } |
| | | |
| | | @Override |
| | | public ByteString normalizeAttributeValue(final Schema schema, final ByteSequence value) |
| | | throws DecodeException { |
| | |
| | | * |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Portions copyright 2014 ForgeRock AS |
| | | * Portions copyright 2014-2015 ForgeRock AS |
| | | */ |
| | | package org.forgerock.opendj.ldap.schema; |
| | | |
| | |
| | | import org.forgerock.opendj.ldap.DecodeException; |
| | | |
| | | import static com.forgerock.opendj.util.StringPrepProfile.*; |
| | | import static org.forgerock.opendj.ldap.schema.SchemaConstants.*; |
| | | |
| | | /** |
| | | * This class implements the caseIgnoreIA5SubstringsMatch matching rule defined |
| | | * in RFC 2252. |
| | | */ |
| | | final class CaseIgnoreIA5SubstringMatchingRuleImpl extends AbstractSubstringMatchingRuleImpl { |
| | | |
| | | CaseIgnoreIA5SubstringMatchingRuleImpl() { |
| | | super(SMR_CASE_IGNORE_IA5_NAME, EMR_CASE_IGNORE_IA5_NAME); |
| | | } |
| | | |
| | | @Override |
| | | public ByteString normalizeAttributeValue(final Schema schema, final ByteSequence value) |
| | | throws DecodeException { |
| | | return normalize(TRIM, value); |
| | |
| | | * |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Portions copyright 2014 ForgeRock AS |
| | | * Portions copyright 2014-2015 ForgeRock AS |
| | | */ |
| | | package org.forgerock.opendj.ldap.schema; |
| | | |
| | | import static com.forgerock.opendj.util.StringPrepProfile.CASE_FOLD; |
| | | |
| | | import org.forgerock.opendj.ldap.ByteSequence; |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | | |
| | | import static com.forgerock.opendj.util.StringPrepProfile.*; |
| | | import static org.forgerock.opendj.ldap.schema.SchemaConstants.*; |
| | | |
| | | /** |
| | | * This class implements the caseIgnoreListMatch matching rule defined in X.520 |
| | | * and referenced in RFC 2252. |
| | | */ |
| | | final class CaseIgnoreListEqualityMatchingRuleImpl extends AbstractEqualityMatchingRuleImpl { |
| | | |
| | | CaseIgnoreListEqualityMatchingRuleImpl() { |
| | | super(EMR_CASE_IGNORE_LIST_NAME); |
| | | } |
| | | |
| | | @Override |
| | | public ByteString normalizeAttributeValue(final Schema schema, final ByteSequence value) { |
| | | return SchemaUtils.normalizeStringListAttributeValue(value, TRIM, CASE_FOLD); |
| | | } |
| | |
| | | * |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Portions copyright 2014 ForgeRock AS |
| | | * Portions copyright 2014-2015 ForgeRock AS |
| | | */ |
| | | package org.forgerock.opendj.ldap.schema; |
| | | |
| | |
| | | import org.forgerock.opendj.ldap.DecodeException; |
| | | |
| | | import static com.forgerock.opendj.util.StringPrepProfile.*; |
| | | import static org.forgerock.opendj.ldap.schema.SchemaConstants.*; |
| | | |
| | | /** |
| | | * This class implements the caseIgnoreListSubstringsMatch matching rule defined |
| | | * in X.520 and referenced in RFC 2252. |
| | | */ |
| | | final class CaseIgnoreListSubstringMatchingRuleImpl extends AbstractSubstringMatchingRuleImpl { |
| | | |
| | | CaseIgnoreListSubstringMatchingRuleImpl() { |
| | | super(SMR_CASE_IGNORE_LIST_NAME, EMR_CASE_IGNORE_LIST_NAME); |
| | | } |
| | | |
| | | @Override |
| | | public ByteString normalizeAttributeValue(final Schema schema, final ByteSequence value) { |
| | | return SchemaUtils.normalizeStringListAttributeValue(value, TRIM, CASE_FOLD); |
| | | } |
| | |
| | | * |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Portions copyright 2014 ForgeRock AS |
| | | * Portions copyright 2014-2015 ForgeRock AS |
| | | */ |
| | | package org.forgerock.opendj.ldap.schema; |
| | | |
| | |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | | |
| | | import static com.forgerock.opendj.util.StringPrepProfile.*; |
| | | import static org.forgerock.opendj.ldap.schema.SchemaConstants.*; |
| | | |
| | | /** |
| | | * This class defines the caseIgnoreOrderingMatch matching rule defined in X.520 |
| | | * and referenced in RFC 2252. |
| | | */ |
| | | final class CaseIgnoreOrderingMatchingRuleImpl extends AbstractOrderingMatchingRuleImpl { |
| | | |
| | | public CaseIgnoreOrderingMatchingRuleImpl() { |
| | | // Reusing equality index since OPENDJ-1864 |
| | | super(EMR_CASE_IGNORE_NAME); |
| | | } |
| | | |
| | | @Override |
| | | public ByteString normalizeAttributeValue(final Schema schema, final ByteSequence value) { |
| | | return SchemaUtils.normalizeStringAttributeValue(value, TRIM, CASE_FOLD); |
| | |
| | | * |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Portions copyright 2014 ForgeRock AS |
| | | * Portions copyright 2014-2015 ForgeRock AS |
| | | */ |
| | | package org.forgerock.opendj.ldap.schema; |
| | | |
| | |
| | | import org.forgerock.opendj.ldap.DecodeException; |
| | | |
| | | import static com.forgerock.opendj.util.StringPrepProfile.*; |
| | | import static org.forgerock.opendj.ldap.schema.SchemaConstants.*; |
| | | |
| | | /** |
| | | * This class defines the caseIgnoreSubstringsMatch matching rule defined in |
| | | * X.520 and referenced in RFC 2252. |
| | | */ |
| | | final class CaseIgnoreSubstringMatchingRuleImpl extends AbstractSubstringMatchingRuleImpl { |
| | | |
| | | CaseIgnoreSubstringMatchingRuleImpl() { |
| | | super(SMR_CASE_IGNORE_NAME, EMR_CASE_IGNORE_NAME); |
| | | } |
| | | |
| | | @Override |
| | | public ByteString normalizeAttributeValue(final Schema schema, final ByteSequence value) { |
| | | return normalize(TRIM, value); |
| | | } |
| | |
| | | * |
| | | * Copyright 2006-2009 Sun Microsystems, Inc. |
| | | * Portions Copyright 2013-2014 Manuel Gaupp |
| | | * Copyright 2014 ForgeRock AS |
| | | * Copyright 2014-2015 ForgeRock AS |
| | | */ |
| | | package org.forgerock.opendj.ldap.schema; |
| | | |
| | |
| | | import com.forgerock.opendj.util.StaticUtils; |
| | | |
| | | import static com.forgerock.opendj.ldap.CoreMessages.*; |
| | | import static org.forgerock.opendj.ldap.schema.SchemaConstants.*; |
| | | |
| | | /** |
| | | * This class implements the certificateExactMatch matching rule defined in |
| | |
| | | */ |
| | | private static final String GSER_ID_RDNSEQUENCE = "rdnSequence"; |
| | | |
| | | CertificateExactMatchingRuleImpl() { |
| | | super(EMR_CERTIFICATE_EXACT_NAME); |
| | | } |
| | | |
| | | /** |
| | | * Retrieves the normalized form of the provided value, which is best suited |
| | | * for efficiently performing matching operations on that value. |
| | |
| | | // Assume the assertion value is a certificate and parse issuer and |
| | | // serial number. If the value is not even a certificate then the |
| | | // raw bytes will be returned. |
| | | return DefaultAssertion.equality(normalizeAttributeValue(schema, value)); |
| | | return defaultAssertion(normalizeAttributeValue(schema, value)); |
| | | } |
| | | |
| | | final BigInteger serialNumber; |
| | |
| | | } |
| | | |
| | | final ByteString certificateIssuer = normalizeDN(schema, dnstring); |
| | | return DefaultAssertion.equality(createEncodedValue(serialNumber, certificateIssuer)); |
| | | return defaultAssertion(createEncodedValue(serialNumber, certificateIssuer)); |
| | | } |
| | | |
| | | private ByteString normalizeDN(final Schema schema, final String dnstring) throws DecodeException { |
| | |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright 2014 ForgeRock AS. |
| | | * Copyright 2014-2015 ForgeRock AS. |
| | | */ |
| | | package org.forgerock.opendj.ldap.schema; |
| | | |
| | | import java.text.Collator; |
| | | import java.util.Arrays; |
| | | import java.util.ArrayList; |
| | | import java.util.Collection; |
| | | import java.util.Collections; |
| | | import java.util.List; |
| | |
| | | import org.forgerock.opendj.ldap.DecodeException; |
| | | import org.forgerock.opendj.ldap.spi.IndexQueryFactory; |
| | | import org.forgerock.opendj.ldap.spi.Indexer; |
| | | import org.forgerock.opendj.ldap.spi.IndexingOptions; |
| | | |
| | | /** |
| | | * Implementations of collation matching rules. Each matching rule is created |
| | |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public Collection<? extends Indexer> getIndexers() { |
| | | public Collection<? extends Indexer> createIndexers(IndexingOptions options) { |
| | | return Collections.singletonList(indexer); |
| | | } |
| | | |
| | |
| | | @Override |
| | | public Assertion getAssertion(final Schema schema, final ByteSequence assertionValue) |
| | | throws DecodeException { |
| | | return DefaultAssertion.named(indexName, normalizeAttributeValue(schema, assertionValue)); |
| | | return named(indexName, normalizeAttributeValue(schema, assertionValue)); |
| | | } |
| | | |
| | | } |
| | |
| | | private static final class CollationSubstringMatchingRuleImpl extends AbstractCollationMatchingRuleImpl { |
| | | |
| | | private final AbstractSubstringMatchingRuleImpl substringMatchingRule; |
| | | private final Indexer subIndexer; |
| | | |
| | | /** |
| | | * Creates the matching rule with the provided locale. |
| | |
| | | return CollationSubstringMatchingRuleImpl.this.normalizeAttributeValue(schema, value); |
| | | } |
| | | }; |
| | | // default substring matching rule has exactly one indexer |
| | | subIndexer = substringMatchingRule.getIndexers().iterator().next(); |
| | | } |
| | | |
| | | @Override |
| | |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public final Collection<? extends Indexer> getIndexers() { |
| | | return Arrays.asList(subIndexer, indexer); |
| | | public final Collection<? extends Indexer> createIndexers(IndexingOptions options) { |
| | | final Collection<Indexer> indexers = new ArrayList<>(substringMatchingRule.createIndexers(options)); |
| | | indexers.add(indexer); |
| | | return indexers; |
| | | } |
| | | } |
| | | |
| | |
| | | * |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Portions copyright 2011-2014 ForgeRock AS |
| | | * Portions copyright 2011-2015 ForgeRock AS |
| | | */ |
| | | package org.forgerock.opendj.ldap.schema; |
| | | |
| | |
| | | |
| | | @Override |
| | | public String getEqualityMatchingRule() { |
| | | return EMR_OID_FIRST_COMPONENT_OID; |
| | | return EMR_OID_FIRST_COMPONENT_NAME; |
| | | } |
| | | |
| | | public String getName() { |
| | |
| | | * |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Portions copyright 2014 ForgeRock AS |
| | | * Portions copyright 2014-2015 ForgeRock AS |
| | | */ |
| | | package org.forgerock.opendj.ldap.schema; |
| | | |
| | |
| | | import static com.forgerock.opendj.util.StringPrepProfile.TRIM; |
| | | import static com.forgerock.opendj.ldap.CoreMessages.ERR_ATTR_SYNTAX_EMPTY_VALUE; |
| | | import static com.forgerock.opendj.ldap.CoreMessages.ERR_ATTR_SYNTAX_EXPECTED_OPEN_PARENTHESIS; |
| | | import static org.forgerock.opendj.ldap.schema.SchemaConstants.EMR_DIRECTORY_STRING_FIRST_COMPONENT_NAME; |
| | | |
| | | import org.forgerock.opendj.ldap.Assertion; |
| | | import org.forgerock.opendj.ldap.ByteSequence; |
| | |
| | | */ |
| | | final class DirectoryStringFirstComponentEqualityMatchingRuleImpl extends AbstractEqualityMatchingRuleImpl { |
| | | |
| | | DirectoryStringFirstComponentEqualityMatchingRuleImpl() { |
| | | super(EMR_DIRECTORY_STRING_FIRST_COMPONENT_NAME); |
| | | } |
| | | |
| | | @Override |
| | | public Assertion getAssertion(final Schema schema, final ByteSequence assertionValue) { |
| | | return DefaultAssertion.equality(SchemaUtils.normalizeStringAttributeValue(assertionValue, TRIM, CASE_FOLD)); |
| | | return named(EMR_DIRECTORY_STRING_FIRST_COMPONENT_NAME, |
| | | SchemaUtils.normalizeStringAttributeValue(assertionValue, TRIM, CASE_FOLD)); |
| | | } |
| | | |
| | | public ByteString normalizeAttributeValue(final Schema schema, final ByteSequence value) |
| | |
| | | * |
| | | * |
| | | * Copyright 2009-2010 Sun Microsystems, Inc. |
| | | * Portions copyright 2011-2014 ForgeRock AS. |
| | | * Portions copyright 2011-2015 ForgeRock AS. |
| | | */ |
| | | package org.forgerock.opendj.ldap.schema; |
| | | |
| | | import static org.forgerock.opendj.ldap.schema.SchemaConstants.*; |
| | | |
| | | import org.forgerock.i18n.LocalizedIllegalArgumentException; |
| | | import org.forgerock.opendj.ldap.ByteSequence; |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | |
| | | */ |
| | | final class DistinguishedNameEqualityMatchingRuleImpl extends AbstractEqualityMatchingRuleImpl { |
| | | |
| | | DistinguishedNameEqualityMatchingRuleImpl() { |
| | | super(EMR_DN_NAME); |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | public ByteString normalizeAttributeValue(final Schema schema, final ByteSequence value) |
| | | throws DecodeException { |
| | |
| | | * |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Portions copyright 2014 ForgeRock AS |
| | | * Portions copyright 2014-2015 ForgeRock AS |
| | | */ |
| | | package org.forgerock.opendj.ldap.schema; |
| | | |
| | | import static org.forgerock.opendj.ldap.schema.SchemaConstants.*; |
| | | |
| | | import org.forgerock.i18n.LocalizableMessage; |
| | | import org.forgerock.i18n.slf4j.LocalizedLogger; |
| | | import org.forgerock.opendj.ldap.ByteSequence; |
| | |
| | | |
| | | private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); |
| | | |
| | | DoubleMetaphoneApproximateMatchingRuleImpl() { |
| | | super(AMR_DOUBLE_METAPHONE_NAME); |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | public ByteString normalizeAttributeValue(final Schema schema, final ByteSequence value) { |
| | | String valueString = value.toString(); |
| | |
| | | * |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Portions Copyright 2015 ForgeRock AS. |
| | | */ |
| | | package org.forgerock.opendj.ldap.schema; |
| | | |
| | | import static com.forgerock.opendj.ldap.CoreMessages.WARN_ATTR_SYNTAX_LDAPSYNTAX_ENUM_INVALID_VALUE; |
| | | import static org.forgerock.opendj.ldap.schema.SchemaConstants.*; |
| | | |
| | | import org.forgerock.opendj.ldap.ByteSequence; |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | |
| | | private final EnumSyntaxImpl syntax; |
| | | |
| | | EnumOrderingMatchingRule(final EnumSyntaxImpl syntax) { |
| | | super(OMR_GENERIC_ENUM_NAME); |
| | | Reject.ifNull(syntax); |
| | | this.syntax = syntax; |
| | | } |
| | | |
| | | @Override |
| | | public ByteString normalizeAttributeValue(final Schema schema, final ByteSequence value) |
| | | throws DecodeException { |
| | | final int index = syntax.indexOf(value); |
| | |
| | | * |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Portions copyright 2012-2014 ForgeRock AS. |
| | | * Portions copyright 2012-2015 ForgeRock AS. |
| | | */ |
| | | package org.forgerock.opendj.ldap.schema; |
| | | |
| | | import static org.forgerock.opendj.ldap.schema.SchemaConstants.*; |
| | | |
| | | import org.forgerock.i18n.LocalizedIllegalArgumentException; |
| | | import org.forgerock.opendj.ldap.ByteSequence; |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | |
| | | * and referenced in RFC 2252. |
| | | */ |
| | | final class GeneralizedTimeEqualityMatchingRuleImpl extends AbstractEqualityMatchingRuleImpl { |
| | | |
| | | GeneralizedTimeEqualityMatchingRuleImpl() { |
| | | super(EMR_GENERALIZED_TIME_NAME); |
| | | } |
| | | |
| | | public ByteString normalizeAttributeValue(final Schema schema, final ByteSequence value) |
| | | throws DecodeException { |
| | | try { |
| | |
| | | * |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Portions copyright 2012 ForgeRock AS. |
| | | * Portions copyright 2012-2015 ForgeRock AS. |
| | | */ |
| | | package org.forgerock.opendj.ldap.schema; |
| | | |
| | | import static org.forgerock.opendj.ldap.schema.SchemaConstants.*; |
| | | |
| | | import org.forgerock.i18n.LocalizedIllegalArgumentException; |
| | | import org.forgerock.opendj.ldap.ByteSequence; |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | |
| | | * X.520 and referenced in RFC 2252. |
| | | */ |
| | | final class GeneralizedTimeOrderingMatchingRuleImpl extends AbstractOrderingMatchingRuleImpl { |
| | | |
| | | GeneralizedTimeOrderingMatchingRuleImpl() { |
| | | // Reusing equality index since OPENDJ-1864 |
| | | super(EMR_GENERALIZED_TIME_NAME); |
| | | } |
| | | |
| | | public ByteString normalizeAttributeValue(final Schema schema, final ByteSequence value) |
| | | throws DecodeException { |
| | | try { |
| | |
| | | package org.forgerock.opendj.ldap.schema; |
| | | |
| | | import static org.forgerock.opendj.ldap.schema.IntegerOrderingMatchingRuleImpl.normalizeValueAndEncode; |
| | | import static org.forgerock.opendj.ldap.schema.SchemaConstants.*; |
| | | |
| | | import org.forgerock.opendj.ldap.ByteSequence; |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | |
| | | * potentially share the same index. |
| | | */ |
| | | final class IntegerEqualityMatchingRuleImpl extends AbstractEqualityMatchingRuleImpl { |
| | | |
| | | IntegerEqualityMatchingRuleImpl() { |
| | | super(EMR_INTEGER_NAME); |
| | | } |
| | | |
| | | @Override |
| | | public ByteString normalizeAttributeValue(final Schema schema, final ByteSequence value) |
| | | throws DecodeException { |
| | |
| | | * |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Portions copyright 2013-2014 ForgeRock AS |
| | | * Portions copyright 2013-2015 ForgeRock AS |
| | | */ |
| | | package org.forgerock.opendj.ldap.schema; |
| | | |
| | | import static com.forgerock.opendj.ldap.CoreMessages.*; |
| | | import static org.forgerock.opendj.ldap.schema.SchemaConstants.*; |
| | | |
| | | import org.forgerock.i18n.LocalizableMessage; |
| | | import org.forgerock.i18n.slf4j.LocalizedLogger; |
| | |
| | | |
| | | private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); |
| | | |
| | | IntegerFirstComponentEqualityMatchingRuleImpl() { |
| | | super(EMR_INTEGER_FIRST_COMPONENT_NAME); |
| | | } |
| | | |
| | | @Override |
| | | public Assertion getAssertion(final Schema schema, final ByteSequence assertionValue) |
| | | throws DecodeException { |
| | |
| | | final String definition = assertionValue.toString(); |
| | | final SubstringReader reader = new SubstringReader(definition); |
| | | final int intValue = SchemaUtils.readRuleID(reader); |
| | | return DefaultAssertion.equality(ByteString.valueOf(intValue)); |
| | | return defaultAssertion(ByteString.valueOf(intValue)); |
| | | } catch (final Exception e) { |
| | | logger.debug(LocalizableMessage.raw("%s", e)); |
| | | |
| | |
| | | package org.forgerock.opendj.ldap.schema; |
| | | |
| | | import static com.forgerock.opendj.ldap.CoreMessages.WARN_ATTR_SYNTAX_ILLEGAL_INTEGER; |
| | | import static org.forgerock.opendj.ldap.schema.SchemaConstants.*; |
| | | |
| | | import java.math.BigInteger; |
| | | |
| | |
| | | } |
| | | } |
| | | |
| | | public IntegerOrderingMatchingRuleImpl() { |
| | | // Reusing equality index since OPENDJ-1864 |
| | | super(EMR_INTEGER_NAME); |
| | | } |
| | | |
| | | @Override |
| | | public ByteString normalizeAttributeValue(final Schema schema, final ByteSequence value) |
| | | throws DecodeException { |
| | |
| | | * |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Portions copyright 2014 ForgeRock AS |
| | | * Portions copyright 2014-2015 ForgeRock AS |
| | | */ |
| | | package org.forgerock.opendj.ldap.schema; |
| | | |
| | | import static com.forgerock.opendj.util.StringPrepProfile.CASE_FOLD; |
| | | import static com.forgerock.opendj.util.StringPrepProfile.TRIM; |
| | | import static org.forgerock.opendj.ldap.schema.SchemaConstants.*; |
| | | |
| | | import java.util.Collection; |
| | | import java.util.Collections; |
| | |
| | | import org.forgerock.opendj.ldap.DecodeException; |
| | | import org.forgerock.opendj.ldap.spi.IndexQueryFactory; |
| | | import org.forgerock.opendj.ldap.spi.Indexer; |
| | | import org.forgerock.opendj.ldap.spi.IndexingOptions; |
| | | |
| | | /** |
| | | * This class implements the keywordMatch matching rule defined in X.520. That |
| | |
| | | * </UL> |
| | | */ |
| | | final class KeywordEqualityMatchingRuleImpl extends AbstractEqualityMatchingRuleImpl { |
| | | |
| | | KeywordEqualityMatchingRuleImpl() { |
| | | super(EMR_KEYWORD_NAME); |
| | | } |
| | | |
| | | @Override |
| | | public Assertion getAssertion(final Schema schema, final ByteSequence assertionValue) |
| | | throws DecodeException { |
| | |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public Collection<? extends Indexer> getIndexers() { |
| | | public Collection<? extends Indexer> createIndexers(IndexingOptions options) { |
| | | return Collections.emptySet(); |
| | | } |
| | | |
| | |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | | import org.forgerock.opendj.ldap.DecodeException; |
| | | import org.forgerock.opendj.ldap.spi.Indexer; |
| | | import org.forgerock.opendj.ldap.spi.IndexingOptions; |
| | | |
| | | /** |
| | | * This class defines a data structure for storing and interacting with matching |
| | |
| | | } |
| | | |
| | | /** |
| | | * Returns the indexers for this matching rule. |
| | | * Returns the indexers for this matching rule configured using the provided indexing options. |
| | | * |
| | | * @param options |
| | | * The indexing options |
| | | * @return the collection of indexers for this matching rule. |
| | | */ |
| | | public Collection<? extends Indexer> getIndexers() { |
| | | return impl.getIndexers(); |
| | | public Collection<? extends Indexer> createIndexers(IndexingOptions options) { |
| | | return impl.createIndexers(options); |
| | | } |
| | | |
| | | /** |
| | |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | | import org.forgerock.opendj.ldap.DecodeException; |
| | | import org.forgerock.opendj.ldap.spi.Indexer; |
| | | import org.forgerock.opendj.ldap.spi.IndexingOptions; |
| | | |
| | | /** |
| | | * This interface defines the set of methods that must be implemented to define |
| | |
| | | |
| | | /** |
| | | * Returns the indexers for this matching rule. |
| | | * |
| | | * @param options |
| | | * The indexing options |
| | | * @return a non null collection of indexers for this matching rule. |
| | | */ |
| | | Collection<? extends Indexer> getIndexers(); |
| | | |
| | | /** |
| | | * Returns whether a backend can build an index for this matching rule. |
| | | * |
| | | * @return true a backend can build an index for this matching rule, |
| | | * false otherwise. |
| | | */ |
| | | boolean isIndexingSupported(); |
| | | Collection<? extends Indexer> createIndexers(IndexingOptions options); |
| | | } |
| | |
| | | * |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Portions copyright 2014 ForgeRock AS |
| | | * Portions copyright 2014-2015 ForgeRock AS |
| | | */ |
| | | package org.forgerock.opendj.ldap.schema; |
| | | |
| | | import static org.forgerock.opendj.ldap.schema.SchemaConstants.*; |
| | | |
| | | import org.forgerock.opendj.ldap.ByteSequence; |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | | |
| | |
| | | * spaces, but ignores spaces when performing matching. |
| | | */ |
| | | final class NumericStringEqualityMatchingRuleImpl extends AbstractEqualityMatchingRuleImpl { |
| | | |
| | | NumericStringEqualityMatchingRuleImpl() { |
| | | super(EMR_NUMERIC_STRING_NAME); |
| | | } |
| | | |
| | | public ByteString normalizeAttributeValue(final Schema schema, final ByteSequence value) { |
| | | return SchemaUtils.normalizeNumericStringAttributeValue(value); |
| | | } |
| | |
| | | * |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Portions copyright 2014 ForgeRock AS |
| | | * Portions copyright 2014-2015 ForgeRock AS |
| | | */ |
| | | package org.forgerock.opendj.ldap.schema; |
| | | |
| | | import static org.forgerock.opendj.ldap.schema.SchemaConstants.*; |
| | | |
| | | import org.forgerock.opendj.ldap.ByteSequence; |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | | |
| | |
| | | * in X.520 and referenced in RFC 2252. |
| | | */ |
| | | final class NumericStringOrderingMatchingRuleImpl extends AbstractOrderingMatchingRuleImpl { |
| | | |
| | | NumericStringOrderingMatchingRuleImpl() { |
| | | // Reusing equality index since OPENDJ-1864 |
| | | super(EMR_NUMERIC_STRING_NAME); |
| | | } |
| | | |
| | | public ByteString normalizeAttributeValue(final Schema schema, final ByteSequence value) { |
| | | return SchemaUtils.normalizeNumericStringAttributeValue(value); |
| | | } |
| | |
| | | * |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Portions copyright 2014 ForgeRock AS |
| | | * Portions copyright 2014-2015 ForgeRock AS |
| | | */ |
| | | package org.forgerock.opendj.ldap.schema; |
| | | |
| | | import static org.forgerock.opendj.ldap.schema.SchemaConstants.*; |
| | | |
| | | import org.forgerock.opendj.ldap.ByteSequence; |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | | |
| | |
| | | * in X.520 and referenced in RFC 2252. |
| | | */ |
| | | final class NumericStringSubstringMatchingRuleImpl extends AbstractSubstringMatchingRuleImpl { |
| | | |
| | | NumericStringSubstringMatchingRuleImpl() { |
| | | super(SMR_NUMERIC_STRING_NAME, EMR_NUMERIC_STRING_NAME); |
| | | } |
| | | |
| | | public ByteString normalizeAttributeValue(final Schema schema, final ByteSequence value) { |
| | | return SchemaUtils.normalizeNumericStringAttributeValue(value); |
| | | } |
| | |
| | | */ |
| | | package org.forgerock.opendj.ldap.schema; |
| | | |
| | | import static org.forgerock.opendj.ldap.schema.SchemaConstants.*; |
| | | import static org.forgerock.opendj.ldap.schema.SchemaOptions.*; |
| | | import static org.forgerock.opendj.ldap.schema.SchemaUtils.*; |
| | | |
| | |
| | | */ |
| | | final class ObjectIdentifierEqualityMatchingRuleImpl extends AbstractEqualityMatchingRuleImpl { |
| | | |
| | | ObjectIdentifierEqualityMatchingRuleImpl() { |
| | | super(EMR_OID_NAME); |
| | | } |
| | | |
| | | static String resolveNames(final Schema schema, final String oid) { |
| | | if (!StaticUtils.isDigit(oid.charAt(0))) { |
| | | // Do an best effort attempt to normalize names to OIDs. |
| | |
| | | import static com.forgerock.opendj.ldap.CoreMessages.*; |
| | | |
| | | import static org.forgerock.opendj.ldap.schema.ObjectIdentifierEqualityMatchingRuleImpl.*; |
| | | import static org.forgerock.opendj.ldap.schema.SchemaConstants.*; |
| | | import static org.forgerock.opendj.ldap.schema.SchemaOptions.*; |
| | | import static org.forgerock.opendj.ldap.schema.SchemaUtils.*; |
| | | |
| | |
| | | */ |
| | | final class ObjectIdentifierFirstComponentEqualityMatchingRuleImpl extends AbstractEqualityMatchingRuleImpl { |
| | | |
| | | ObjectIdentifierFirstComponentEqualityMatchingRuleImpl() { |
| | | super(EMR_OID_FIRST_COMPONENT_NAME); |
| | | } |
| | | |
| | | @Override |
| | | public Assertion getAssertion(final Schema schema, final ByteSequence assertionValue) throws DecodeException { |
| | | return DefaultAssertion.equality(normalizeAttributeValuePrivate(schema, assertionValue)); |
| | | return defaultAssertion(normalizeAttributeValuePrivate(schema, assertionValue)); |
| | | } |
| | | |
| | | @Override |
| | |
| | | * |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Portions copyright 2014 ForgeRock AS |
| | | * Portions copyright 2014-2015 ForgeRock AS |
| | | */ |
| | | package org.forgerock.opendj.ldap.schema; |
| | | |
| | | import static org.forgerock.opendj.ldap.schema.SchemaConstants.*; |
| | | |
| | | import org.forgerock.opendj.ldap.ByteSequence; |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | | |
| | |
| | | * string syntaxes. |
| | | */ |
| | | final class OctetStringEqualityMatchingRuleImpl extends AbstractEqualityMatchingRuleImpl { |
| | | |
| | | OctetStringEqualityMatchingRuleImpl() { |
| | | super(EMR_OCTET_STRING_NAME); |
| | | } |
| | | |
| | | public ByteString normalizeAttributeValue(final Schema schema, final ByteSequence value) { |
| | | return value.toByteString(); |
| | | } |
| | |
| | | * |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Portions copyright 2015 ForgeRock AS. |
| | | */ |
| | | package org.forgerock.opendj.ldap.schema; |
| | | |
| | | import static org.forgerock.opendj.ldap.schema.SchemaConstants.*; |
| | | |
| | | import org.forgerock.opendj.ldap.ByteSequence; |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | | |
| | |
| | | * octet string syntaxes. |
| | | */ |
| | | final class OctetStringOrderingMatchingRuleImpl extends AbstractOrderingMatchingRuleImpl { |
| | | |
| | | OctetStringOrderingMatchingRuleImpl() { |
| | | // Reusing equality index since OPENDJ-1864 |
| | | super(EMR_OCTET_STRING_NAME); |
| | | } |
| | | |
| | | public ByteString normalizeAttributeValue(final Schema schema, final ByteSequence value) { |
| | | return value.toByteString(); |
| | | } |
| | |
| | | * |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Portions Copyright 2015 ForgeRock AS. |
| | | */ |
| | | package org.forgerock.opendj.ldap.schema; |
| | | |
| | | import static org.forgerock.opendj.ldap.schema.SchemaConstants.*; |
| | | |
| | | import org.forgerock.opendj.ldap.ByteSequence; |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | | |
| | |
| | | * and octet string syntaxes. |
| | | */ |
| | | final class OctetStringSubstringMatchingRuleImpl extends AbstractSubstringMatchingRuleImpl { |
| | | |
| | | OctetStringSubstringMatchingRuleImpl() { |
| | | super(SMR_OCTET_STRING_NAME, EMR_OCTET_STRING_NAME); |
| | | } |
| | | |
| | | public ByteString normalizeAttributeValue(final Schema schema, final ByteSequence value) { |
| | | return value.toByteString(); |
| | | } |
| | |
| | | * |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Portions copyright 2014 ForgeRock AS |
| | | * Portions copyright 2014-2015 ForgeRock AS |
| | | */ |
| | | package org.forgerock.opendj.ldap.schema; |
| | | |
| | |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | | |
| | | import static com.forgerock.opendj.util.StringPrepProfile.*; |
| | | import static org.forgerock.opendj.ldap.schema.SchemaConstants.*; |
| | | |
| | | /** |
| | | * This class implements the presentationAddressMatch matching rule defined in |
| | |
| | | * like the caseIgnoreMatch rule. |
| | | */ |
| | | final class PresentationAddressEqualityMatchingRuleImpl extends AbstractEqualityMatchingRuleImpl { |
| | | |
| | | PresentationAddressEqualityMatchingRuleImpl() { |
| | | super(EMR_PRESENTATION_ADDRESS_NAME); |
| | | } |
| | | |
| | | @Override |
| | | public ByteString normalizeAttributeValue(final Schema schema, final ByteSequence value) { |
| | | return SchemaUtils.normalizeStringAttributeValue(value, TRIM, CASE_FOLD); |
| | |
| | | * |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Portions copyright 2014 ForgeRock AS |
| | | * Portions copyright 2014-2015 ForgeRock AS |
| | | */ |
| | | package org.forgerock.opendj.ldap.schema; |
| | | |
| | |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | | |
| | | import static com.forgerock.opendj.util.StringPrepProfile.*; |
| | | import static org.forgerock.opendj.ldap.schema.SchemaConstants.*; |
| | | |
| | | /** |
| | | * This class implements the protocolInformationMatch matching rule defined in |
| | |
| | | * like the caseIgnoreMatch rule. |
| | | */ |
| | | final class ProtocolInformationEqualityMatchingRuleImpl extends AbstractEqualityMatchingRuleImpl { |
| | | |
| | | ProtocolInformationEqualityMatchingRuleImpl() { |
| | | super(EMR_PROTOCOL_INFORMATION_NAME); |
| | | } |
| | | |
| | | @Override |
| | | public ByteString normalizeAttributeValue(final Schema schema, final ByteSequence value) { |
| | | return SchemaUtils.normalizeStringAttributeValue(value, TRIM, CASE_FOLD); |
| | |
| | | * |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Portions copyright 2014 ForgeRock AS |
| | | * Portions copyright 2014-2015 ForgeRock AS |
| | | */ |
| | | package org.forgerock.opendj.ldap.schema; |
| | | |
| | | import static org.forgerock.opendj.ldap.schema.SchemaConstants.*; |
| | | |
| | | import org.forgerock.opendj.ldap.ByteSequence; |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | | |
| | |
| | | * only numeric digits and strip out everything else. |
| | | */ |
| | | final class TelephoneNumberEqualityMatchingRuleImpl extends AbstractEqualityMatchingRuleImpl { |
| | | |
| | | TelephoneNumberEqualityMatchingRuleImpl() { |
| | | super(EMR_TELEPHONE_NAME); |
| | | } |
| | | |
| | | public ByteString normalizeAttributeValue(final Schema schema, final ByteSequence value) { |
| | | final String valueString = value.toString(); |
| | | final int valueLength = valueString.length(); |
| | |
| | | * |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Portions Copyright 2015 ForgeRock AS. |
| | | */ |
| | | package org.forgerock.opendj.ldap.schema; |
| | | |
| | | import static org.forgerock.opendj.ldap.schema.SchemaConstants.*; |
| | | |
| | | import org.forgerock.opendj.ldap.ByteSequence; |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | | |
| | |
| | | * this matching will compare only numeric digits and strip out everything else. |
| | | */ |
| | | final class TelephoneNumberSubstringMatchingRuleImpl extends AbstractSubstringMatchingRuleImpl { |
| | | |
| | | TelephoneNumberSubstringMatchingRuleImpl() { |
| | | super(SMR_TELEPHONE_NAME, EMR_TELEPHONE_NAME); |
| | | } |
| | | |
| | | public ByteString normalizeAttributeValue(final Schema schema, final ByteSequence value) { |
| | | final String valueString = value.toString(); |
| | | final int valueLength = valueString.length(); |
| | |
| | | import org.forgerock.opendj.ldap.spi.IndexQueryFactory; |
| | | import org.forgerock.opendj.ldap.spi.Indexer; |
| | | import org.forgerock.opendj.ldap.spi.IndexingOptions; |
| | | |
| | | import org.forgerock.util.time.TimeService; |
| | | |
| | | import static com.forgerock.opendj.ldap.CoreMessages.*; |
| | | import static com.forgerock.opendj.util.StaticUtils.*; |
| | | |
| | | import static org.forgerock.opendj.ldap.DecodeException.*; |
| | | import static org.forgerock.opendj.ldap.schema.SchemaConstants.*; |
| | | |
| | | /** |
| | | * Implementations of time-based matching rules. |
| | | */ |
| | | final class TimeBasedMatchingRulesImpl { |
| | | |
| | | private static final String RELATIVE_TIME_INDEX_ID = "rt"; |
| | | private static final String PARTIAL_DATE_TIME_INDEX_ID = "pdt"; |
| | | private static final String EXTENSIBLE_INDEX_ID = "ext"; |
| | | |
| | | private static final TimeZone TIME_ZONE_UTC = TimeZone.getTimeZone("UTC"); |
| | | |
| | | /** Constants for generating keys. */ |
| | |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public ByteString normalizeAttributeValue(Schema schema, ByteSequence value) throws DecodeException { |
| | | public final ByteString normalizeAttributeValue(Schema schema, ByteSequence value) throws DecodeException { |
| | | try { |
| | | return ByteString.valueOf(GeneralizedTime.valueOf(value.toString()).getTimeInMillis()); |
| | | } catch (final LocalizedIllegalArgumentException e) { |
| | |
| | | */ |
| | | private static abstract class RelativeTimeOrderingMatchingRuleImpl extends TimeBasedMatchingRuleImpl { |
| | | |
| | | final Indexer indexer = new DefaultIndexer(RELATIVE_TIME_INDEX_ID + "." + EXTENSIBLE_INDEX_ID); |
| | | final Indexer indexer = new DefaultIndexer(EMR_GENERALIZED_TIME_NAME); |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public Collection<? extends Indexer> getIndexers() { |
| | | public Collection<? extends Indexer> createIndexers(IndexingOptions options) { |
| | | return Collections.singletonList(indexer); |
| | | } |
| | | |
| | |
| | | */ |
| | | private static final class PartialDateAndTimeMatchingRuleImpl extends TimeBasedMatchingRuleImpl { |
| | | |
| | | final Indexer indexer = new PartialDateAndTimeIndexer(this); |
| | | private final Indexer indexer = new PartialDateAndTimeIndexer(this); |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public Collection<? extends Indexer> getIndexers() { |
| | | public Collection<? extends Indexer> createIndexers(IndexingOptions options) { |
| | | return Collections.singletonList(indexer); |
| | | } |
| | | |
| | |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public void createKeys(Schema schema, ByteSequence value, IndexingOptions options, |
| | | Collection<ByteString> keys) { |
| | | public void createKeys(Schema schema, ByteSequence value, Collection<ByteString> keys) { |
| | | matchingRule.timeKeys(value, keys); |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public String getIndexID() { |
| | | return PARTIAL_DATE_TIME_INDEX_ID + "." + EXTENSIBLE_INDEX_ID; |
| | | return MR_PARTIAL_DATE_AND_TIME_NAME; |
| | | } |
| | | } |
| | | } |
| | |
| | | * |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Portions copyright 2014 ForgeRock AS |
| | | * Portions copyright 2014-2015 ForgeRock AS |
| | | */ |
| | | package org.forgerock.opendj.ldap.schema; |
| | | |
| | | import static com.forgerock.opendj.ldap.CoreMessages.WARN_ATTR_SYNTAX_UUID_EXPECTED_DASH; |
| | | import static com.forgerock.opendj.ldap.CoreMessages.WARN_ATTR_SYNTAX_UUID_EXPECTED_HEX; |
| | | import static com.forgerock.opendj.ldap.CoreMessages.WARN_ATTR_SYNTAX_UUID_INVALID_LENGTH; |
| | | import static org.forgerock.opendj.ldap.schema.SchemaConstants.*; |
| | | |
| | | import org.forgerock.i18n.LocalizableMessage; |
| | | import org.forgerock.opendj.ldap.ByteSequence; |
| | |
| | | * be used as the default equality matching rule for the UUID syntax. |
| | | */ |
| | | final class UUIDEqualityMatchingRuleImpl extends AbstractEqualityMatchingRuleImpl { |
| | | |
| | | UUIDEqualityMatchingRuleImpl() { |
| | | super(EMR_UUID_NAME); |
| | | } |
| | | |
| | | public ByteString normalizeAttributeValue(final Schema schema, final ByteSequence value) |
| | | throws DecodeException { |
| | | if (value.length() != 36) { |
| | |
| | | * |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Portions copyright 2015 ForgeRock AS. |
| | | */ |
| | | package org.forgerock.opendj.ldap.schema; |
| | | |
| | | import static com.forgerock.opendj.ldap.CoreMessages.WARN_ATTR_SYNTAX_UUID_EXPECTED_DASH; |
| | | import static com.forgerock.opendj.ldap.CoreMessages.WARN_ATTR_SYNTAX_UUID_EXPECTED_HEX; |
| | | import static com.forgerock.opendj.ldap.CoreMessages.WARN_ATTR_SYNTAX_UUID_INVALID_LENGTH; |
| | | import static org.forgerock.opendj.ldap.schema.SchemaConstants.*; |
| | | |
| | | import org.forgerock.i18n.LocalizableMessage; |
| | | import org.forgerock.opendj.ldap.ByteSequence; |
| | |
| | | * This will be the default ordering matching rule for the UUID syntax. |
| | | */ |
| | | final class UUIDOrderingMatchingRuleImpl extends AbstractOrderingMatchingRuleImpl { |
| | | |
| | | UUIDOrderingMatchingRuleImpl() { |
| | | // Reusing equality index since OPENDJ-1864 |
| | | super(EMR_UUID_NAME); |
| | | } |
| | | |
| | | public ByteString normalizeAttributeValue(final Schema schema, final ByteSequence value) |
| | | throws DecodeException { |
| | | if (value.length() != 36) { |
| | |
| | | * |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Portions copyright 2014 ForgeRock AS |
| | | * Portions copyright 2014-2015 ForgeRock AS |
| | | */ |
| | | package org.forgerock.opendj.ldap.schema; |
| | | |
| | | import static org.forgerock.opendj.ldap.schema.SchemaConstants.*; |
| | | |
| | | import org.forgerock.i18n.LocalizedIllegalArgumentException; |
| | | import org.forgerock.opendj.ldap.ByteSequence; |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | |
| | | */ |
| | | final class UniqueMemberEqualityMatchingRuleImpl extends AbstractEqualityMatchingRuleImpl { |
| | | |
| | | UniqueMemberEqualityMatchingRuleImpl() { |
| | | super(EMR_UNIQUE_MEMBER_NAME); |
| | | } |
| | | |
| | | public ByteString normalizeAttributeValue(final Schema schema, final ByteSequence value) throws DecodeException { |
| | | // Separate value into normalized DN and "optional uid" portion. |
| | | final String stringValue = value.toString().trim(); |
| | |
| | | * |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Portions copyright 2014 ForgeRock AS |
| | | * Portions copyright 2014-2015 ForgeRock AS |
| | | */ |
| | | package org.forgerock.opendj.ldap.schema; |
| | | |
| | | import static org.forgerock.opendj.ldap.schema.SchemaConstants.*; |
| | | |
| | | import org.forgerock.opendj.ldap.ByteSequence; |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | | import org.forgerock.opendj.ldap.DecodeException; |
| | |
| | | * equal to each other. |
| | | */ |
| | | final class UserPasswordExactEqualityMatchingRuleImpl extends AbstractEqualityMatchingRuleImpl { |
| | | |
| | | UserPasswordExactEqualityMatchingRuleImpl() { |
| | | super(EMR_USER_PASSWORD_EXACT_NAME); |
| | | } |
| | | |
| | | public ByteString normalizeAttributeValue(final Schema schema, final ByteSequence value) |
| | | throws DecodeException { |
| | | // The normalized form of this matching rule is exactly equal to the |
| | |
| | | * |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Portions copyright 2014 ForgeRock AS |
| | | * Portions copyright 2014-2015 ForgeRock AS |
| | | */ |
| | | package org.forgerock.opendj.ldap.spi; |
| | | |
| | |
| | | * The schema in which the associated matching rule is defined. |
| | | * @param value |
| | | * The attribute value for which keys are required. |
| | | * @param options |
| | | * The indexing options |
| | | * @param keys |
| | | * A collection where to add the created keys. |
| | | * @throws DecodeException if an error occurs while normalizing the value |
| | | */ |
| | | void createKeys(Schema schema, ByteSequence value, IndexingOptions options, |
| | | Collection<ByteString> keys) throws DecodeException; |
| | | void createKeys(Schema schema, ByteSequence value, Collection<ByteString> keys) throws DecodeException; |
| | | |
| | | } |
| | |
| | | import org.testng.annotations.Test; |
| | | |
| | | import static org.forgerock.opendj.ldap.ByteString.*; |
| | | import static org.forgerock.opendj.ldap.schema.SchemaConstants.*; |
| | | import static org.mockito.Mockito.*; |
| | | import static org.testng.Assert.*; |
| | | |
| | |
| | | |
| | | private static class FakeSubstringMatchingRuleImpl extends AbstractSubstringMatchingRuleImpl { |
| | | |
| | | FakeSubstringMatchingRuleImpl() { |
| | | super(SMR_CASE_EXACT_OID, EMR_CASE_EXACT_OID); |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public ByteString normalizeAttributeValue(Schema schema, ByteSequence value) throws DecodeException { |
| | |
| | | assertEquals( |
| | | assertion.createIndexQuery(new FakeIndexQueryFactory(newIndexingOptions())), |
| | | "intersect[" |
| | | + "exactMatch(substring, value=='his'), " |
| | | + "exactMatch(substring, value=='thi')" |
| | | + "exactMatch(" + SMR_CASE_EXACT_OID + ", value=='his'), " |
| | | + "exactMatch(" + SMR_CASE_EXACT_OID + ", value=='thi')" |
| | | + "]"); |
| | | } |
| | | |
| | |
| | | assertEquals( |
| | | assertion.createIndexQuery(new FakeIndexQueryFactory(newIndexingOptions())), |
| | | "intersect[" |
| | | + "rangeMatch(equality, 'abc' <= value < 'abd'), " |
| | | + "exactMatch(substring, value=='def'), " |
| | | + "exactMatch(substring, value=='ghi'), " |
| | | + "exactMatch(substring, value=='jkl'), " |
| | | + "exactMatch(substring, value=='abc')" |
| | | + "rangeMatch(" + EMR_CASE_EXACT_OID + ", 'abc' <= value < 'abd'), " |
| | | + "exactMatch(" + SMR_CASE_EXACT_OID + ", value=='def'), " |
| | | + "exactMatch(" + SMR_CASE_EXACT_OID + ", value=='ghi'), " |
| | | + "exactMatch(" + SMR_CASE_EXACT_OID + ", value=='jkl'), " |
| | | + "exactMatch(" + SMR_CASE_EXACT_OID + ", value=='abc')" |
| | | + "]"); |
| | | } |
| | | |
| | |
| | | assertEquals( |
| | | assertion.createIndexQuery(new FakeIndexQueryFactory(newIndexingOptions())), |
| | | "intersect[" |
| | | + "rangeMatch(equality, 'aa' <= value < 'ab'), " |
| | | + "rangeMatch(substring, 'aa' <= value < 'ab')" |
| | | + "rangeMatch(" + EMR_CASE_EXACT_OID + ", 'aa' <= value < 'ab'), " |
| | | + "rangeMatch(" + SMR_CASE_EXACT_OID + ", 'aa' <= value < 'ab')" |
| | | + "]"); |
| | | } |
| | | |
| | |
| | | // 0x00 is the nul byte, a.k.a. string terminator |
| | | // so everything after it is not part of the string |
| | | "intersect[" |
| | | + "rangeMatch(equality, '" + lower + "' <= value < 'b\u0000'), " |
| | | + "rangeMatch(substring, '" + lower + "' <= value < 'b\u0000')" |
| | | + "rangeMatch(" + EMR_CASE_EXACT_OID + ", '" + lower + "' <= value < 'b\u0000'), " |
| | | + "rangeMatch(" + SMR_CASE_EXACT_OID + ", '" + lower + "' <= value < 'b\u0000')" |
| | | + "]"); |
| | | } |
| | | |
| | | @Test |
| | | public void testIndexer() throws Exception { |
| | | final Indexer indexer = getRule().getIndexers().iterator().next(); |
| | | Assertions.assertThat(indexer.getIndexID()).isEqualTo("substring"); |
| | | |
| | | final IndexingOptions options = newIndexingOptions(); |
| | | final Indexer indexer = getRule().createIndexers(options).iterator().next(); |
| | | Assertions.assertThat(indexer.getIndexID()).isEqualTo(SMR_CASE_EXACT_OID + ":" + options.substringKeySize()); |
| | | |
| | | final TreeSet<ByteString> keys = new TreeSet<>(); |
| | | indexer.createKeys(Schema.getCoreSchema(), valueOf("ABCDE"), options, keys); |
| | | indexer.createKeys(Schema.getCoreSchema(), valueOf("ABCDE"), keys); |
| | | Assertions.assertThat(keys).containsOnly((Object[]) toByteStrings("ABC", "BCD", "CDE", "DE", "E")); |
| | | } |
| | | |
| | |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright 2014 ForgeRock AS. |
| | | * Copyright 2014-2015 ForgeRock AS. |
| | | */ |
| | | package org.forgerock.opendj.ldap.schema; |
| | | |
| | |
| | | import org.forgerock.opendj.ldap.schema.AbstractSubstringMatchingRuleImplTest.FakeIndexQueryFactory; |
| | | import org.testng.annotations.DataProvider; |
| | | import org.testng.annotations.Test; |
| | | |
| | | import org.forgerock.util.time.TimeService; |
| | | |
| | | import static org.fest.assertions.Assertions.*; |
| | | import static org.forgerock.opendj.ldap.schema.AbstractSubstringMatchingRuleImplTest.*; |
| | | import static org.forgerock.opendj.ldap.schema.SchemaConstants.*; |
| | | |
| | | @SuppressWarnings("javadoc") |
| | | @Test |
| | |
| | | Assertion assertion = getRule().getAssertion(ByteString.valueOf("2012Y")); |
| | | |
| | | String indexQuery = assertion.createIndexQuery(new FakeIndexQueryFactory(newIndexingOptions(), false)); |
| | | assertThat(indexQuery).matches("intersect\\[exactMatch\\(pdt\\.ext, value=='[0-9A-Z ]*'\\)\\]"); |
| | | assertThat(indexQuery).matches( |
| | | "intersect\\[exactMatch\\(" + MR_PARTIAL_DATE_AND_TIME_NAME + ", value=='[0-9A-Z ]*'\\)\\]"); |
| | | } |
| | | } |
| | |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright 2014 ForgeRock AS. |
| | | * Copyright 2014-2015 ForgeRock AS. |
| | | */ |
| | | package org.forgerock.opendj.ldap.schema; |
| | | |
| | |
| | | |
| | | import static org.fest.assertions.Assertions.*; |
| | | import static org.forgerock.opendj.ldap.schema.AbstractSubstringMatchingRuleImplTest.*; |
| | | import static org.forgerock.opendj.ldap.schema.SchemaConstants.*; |
| | | |
| | | @SuppressWarnings("javadoc") |
| | | @Test |
| | |
| | | Assertion assertion = getRule().getAssertion(ByteString.valueOf("+5m")); |
| | | |
| | | String indexQuery = assertion.createIndexQuery(new FakeIndexQueryFactory(newIndexingOptions(), false)); |
| | | assertThat(indexQuery).startsWith("rangeMatch(rt.ext, '").endsWith("' < value < '')"); |
| | | assertThat(indexQuery).startsWith("rangeMatch(" + EMR_GENERALIZED_TIME_NAME + ", '") |
| | | .endsWith("' < value < '')"); |
| | | } |
| | | } |
| | |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright 2014 ForgeRock AS. |
| | | * Copyright 2014-2015 ForgeRock AS. |
| | | */ |
| | | package org.forgerock.opendj.ldap.schema; |
| | | |
| | |
| | | |
| | | import static org.fest.assertions.Assertions.*; |
| | | import static org.forgerock.opendj.ldap.schema.AbstractSubstringMatchingRuleImplTest.*; |
| | | import static org.forgerock.opendj.ldap.schema.SchemaConstants.*; |
| | | |
| | | @SuppressWarnings("javadoc") |
| | | @Test |
| | |
| | | Assertion assertion = getRule().getAssertion(ByteString.valueOf("+5m")); |
| | | |
| | | String indexQuery = assertion.createIndexQuery(new FakeIndexQueryFactory(newIndexingOptions(), false)); |
| | | assertThat(indexQuery).startsWith("rangeMatch(rt.ext, '' < value < '"); |
| | | assertThat(indexQuery).startsWith("rangeMatch(" + EMR_GENERALIZED_TIME_NAME + ", '' < value < '"); |
| | | } |
| | | } |
| | |
| | | package org.opends.server.backends.jeb; |
| | | |
| | | import static org.opends.messages.BackendMessages.*; |
| | | import static org.opends.server.util.ServerConstants.*; |
| | | import static org.opends.server.util.StaticUtils.*; |
| | | |
| | | import java.io.Closeable; |
| | |
| | | import org.forgerock.opendj.ldap.DecodeException; |
| | | import org.forgerock.opendj.ldap.schema.MatchingRule; |
| | | import org.forgerock.opendj.ldap.spi.IndexQueryFactory; |
| | | import org.forgerock.opendj.ldap.spi.Indexer; |
| | | import org.forgerock.opendj.ldap.spi.IndexingOptions; |
| | | import org.forgerock.util.Utils; |
| | | import org.opends.server.admin.server.ConfigurationChangeListener; |
| | |
| | | |
| | | /** The attribute index configuration. */ |
| | | private LocalDBIndexCfg indexConfig; |
| | | private IndexingOptions indexingOptions; |
| | | |
| | | /** The mapping from names to indexes. */ |
| | | private final Map<String, Index> nameToIndexes = new HashMap<String, Index>(); |
| | | private final IndexQueryFactory<IndexQuery> indexQueryFactory; |
| | | |
| | | /** |
| | | * The mapping from extensible index types (e.g. "substring" or "shared") to list of indexes. |
| | | */ |
| | | private Map<String, Collection<Index>> extensibleIndexesMapping; |
| | | private Map<String, Index> indexIdToIndexes; |
| | | private IndexQueryFactory<IndexQuery> indexQueryFactory; |
| | | |
| | | /** |
| | | * Create a new attribute index object. |
| | |
| | | { |
| | | this.entryContainer = entryContainer; |
| | | this.indexConfig = indexConfig; |
| | | |
| | | buildPresenceIndex(); |
| | | buildIndexes(IndexType.EQUALITY); |
| | | buildIndexes(IndexType.SUBSTRING); |
| | | buildIndexes(IndexType.ORDERING); |
| | | buildIndexes(IndexType.APPROXIMATE); |
| | | buildExtensibleIndexes(); |
| | | |
| | | final JEIndexConfig config = new JEIndexConfig(indexConfig.getSubstringLength()); |
| | | indexQueryFactory = new IndexQueryFactoryImpl(nameToIndexes, config, indexConfig.getAttribute()); |
| | | extensibleIndexesMapping = computeExtensibleIndexesMapping(); |
| | | this.indexingOptions = new JEIndexingOptions(indexConfig.getSubstringLength()); |
| | | this.indexIdToIndexes = Collections.unmodifiableMap(buildIndexes(entryContainer, indexConfig, indexingOptions)); |
| | | this.indexQueryFactory = new IndexQueryFactoryImpl(indexIdToIndexes, indexingOptions, indexConfig.getAttribute()); |
| | | } |
| | | |
| | | private void buildPresenceIndex() |
| | | private static Map<String, Index> buildIndexes(EntryContainer entryContainer, |
| | | LocalDBIndexCfg config, |
| | | IndexingOptions options) throws ConfigException |
| | | { |
| | | final IndexType indexType = IndexType.PRESENCE; |
| | | if (indexConfig.getIndexType().contains(indexType)) |
| | | { |
| | | String indexID = indexType.toString(); |
| | | nameToIndexes.put(indexID, newPresenceIndex(indexConfig)); |
| | | final Map<String, Index> indexes = new HashMap<>(); |
| | | final AttributeType attributeType = config.getAttribute(); |
| | | final int indexEntryLimit = config.getIndexEntryLimit(); |
| | | |
| | | for(IndexType indexType : config.getIndexType()) { |
| | | Collection<? extends Indexer> indexers; |
| | | switch (indexType) |
| | | { |
| | | case PRESENCE: |
| | | indexes.put(indexType.toString(), newPresenceIndex(entryContainer, config)); |
| | | indexers = Collections.emptyList(); |
| | | break; |
| | | case EXTENSIBLE: |
| | | indexers = getExtensibleIndexers(config.getAttribute(), config.getIndexExtensibleMatchingRule(), options); |
| | | break; |
| | | case APPROXIMATE: |
| | | indexers = |
| | | throwIfNoMatchingRule(attributeType, indexType, attributeType.getApproximateMatchingRule()) |
| | | .createIndexers(options); |
| | | break; |
| | | case EQUALITY: |
| | | indexers = |
| | | throwIfNoMatchingRule(attributeType, indexType, attributeType.getEqualityMatchingRule()) |
| | | .createIndexers(options); |
| | | break; |
| | | case ORDERING: |
| | | indexers = |
| | | throwIfNoMatchingRule(attributeType, indexType, attributeType.getOrderingMatchingRule()) |
| | | .createIndexers(options); |
| | | break; |
| | | case SUBSTRING: |
| | | indexers = |
| | | throwIfNoMatchingRule(attributeType, indexType, attributeType.getSubstringMatchingRule()) |
| | | .createIndexers(options); |
| | | break; |
| | | default: |
| | | throw new ConfigException(ERR_CONFIG_INDEX_TYPE_NEEDS_MATCHING_RULE.get(attributeType, indexType.toString())); |
| | | } |
| | | buildAndRegisterIndexesWithIndexers(entryContainer, attributeType, indexEntryLimit, indexers, indexes); |
| | | } |
| | | |
| | | return indexes; |
| | | } |
| | | |
| | | private Index newPresenceIndex(LocalDBIndexCfg cfg) |
| | | private static Index newPresenceIndex(EntryContainer entryContainer, LocalDBIndexCfg cfg) |
| | | { |
| | | final AttributeType attrType = cfg.getAttribute(); |
| | | final String indexName = getIndexName(attrType, IndexType.PRESENCE.toString()); |
| | | final String indexName = getIndexName(entryContainer, attrType, IndexType.PRESENCE.toString()); |
| | | final PresenceIndexer indexer = new PresenceIndexer(attrType); |
| | | return entryContainer.newIndexForAttribute(indexName, indexer, cfg.getIndexEntryLimit()); |
| | | } |
| | | |
| | | private void buildExtensibleIndexes() throws ConfigException |
| | | private static MatchingRule throwIfNoMatchingRule(AttributeType attributeType, IndexType type, MatchingRule rule) |
| | | throws ConfigException |
| | | { |
| | | final IndexType indexType = IndexType.EXTENSIBLE; |
| | | if (indexConfig.getIndexType().contains(indexType)) |
| | | if (rule == null) |
| | | { |
| | | final AttributeType attrType = indexConfig.getAttribute(); |
| | | Set<String> extensibleRules = indexConfig.getIndexExtensibleMatchingRule(); |
| | | if (extensibleRules == null || extensibleRules.isEmpty()) |
| | | { |
| | | throw new ConfigException(ERR_CONFIG_INDEX_TYPE_NEEDS_MATCHING_RULE.get(attrType, indexType.toString())); |
| | | } |
| | | throw new ConfigException(ERR_CONFIG_INDEX_TYPE_NEEDS_MATCHING_RULE.get(attributeType, type.toString())); |
| | | } |
| | | return rule; |
| | | } |
| | | |
| | | // Iterate through the Set and create the index only if necessary. |
| | | // Collation equality and Ordering matching rules share the same indexer and index |
| | | // A Collation substring matching rule is treated differently |
| | | // as it uses a separate indexer and index. |
| | | for (final String ruleName : extensibleRules) |
| | | private static void buildAndRegisterIndexesWithIndexers(EntryContainer entryContainer, |
| | | AttributeType attributeType, |
| | | int indexEntryLimit, |
| | | Collection<? extends Indexer> indexers, |
| | | Map<String, Index> indexes) |
| | | { |
| | | for (Indexer indexer : indexers) |
| | | { |
| | | final String indexID = indexer.getIndexID(); |
| | | if (!indexes.containsKey(indexID)) |
| | | { |
| | | MatchingRule rule = DirectoryServer.getMatchingRule(toLowerCase(ruleName)); |
| | | if (rule == null) |
| | | { |
| | | logger.error(ERR_CONFIG_INDEX_TYPE_NEEDS_VALID_MATCHING_RULE, attrType, ruleName); |
| | | continue; |
| | | } |
| | | for (org.forgerock.opendj.ldap.spi.Indexer indexer : rule.getIndexers()) |
| | | { |
| | | final String indexId = indexer.getIndexID(); |
| | | if (!nameToIndexes.containsKey(indexId)) |
| | | { |
| | | // There is no index available for this index id. Create a new index |
| | | nameToIndexes.put(indexId, newAttributeIndex(indexConfig, indexer)); |
| | | } |
| | | } |
| | | final Index index = newAttributeIndex(entryContainer, attributeType, indexer, indexEntryLimit); |
| | | indexes.put(indexID, index); |
| | | } |
| | | } |
| | | } |
| | | |
| | | private void buildIndexes(IndexType indexType) throws ConfigException |
| | | private static Collection<Indexer> getExtensibleIndexers(AttributeType attributeType, Set<String> extensibleRules, |
| | | IndexingOptions options) throws ConfigException |
| | | { |
| | | if (indexConfig.getIndexType().contains(indexType)) |
| | | if (extensibleRules == null || extensibleRules.isEmpty()) |
| | | { |
| | | final AttributeType attrType = indexConfig.getAttribute(); |
| | | final String indexID = indexType.toString(); |
| | | final MatchingRule rule = getMatchingRule(indexType, attrType); |
| | | throw new ConfigException( |
| | | ERR_CONFIG_INDEX_TYPE_NEEDS_MATCHING_RULE.get(attributeType, IndexType.EXTENSIBLE.toString())); |
| | | } |
| | | |
| | | final Collection<Indexer> indexers = new ArrayList<>(); |
| | | for (final String ruleName : extensibleRules) |
| | | { |
| | | final MatchingRule rule = DirectoryServer.getMatchingRule(toLowerCase(ruleName)); |
| | | if (rule == null) |
| | | { |
| | | throw new ConfigException(ERR_CONFIG_INDEX_TYPE_NEEDS_MATCHING_RULE.get(attrType, indexID)); |
| | | logger.error(ERR_CONFIG_INDEX_TYPE_NEEDS_VALID_MATCHING_RULE, attributeType, ruleName); |
| | | continue; |
| | | } |
| | | |
| | | for (org.forgerock.opendj.ldap.spi.Indexer indexer : rule.getIndexers()) |
| | | { |
| | | nameToIndexes.put(indexID, newAttributeIndex(indexConfig, indexer)); |
| | | } |
| | | indexers.addAll(rule.createIndexers(options)); |
| | | } |
| | | |
| | | return indexers; |
| | | } |
| | | |
| | | private MatchingRule getMatchingRule(IndexType indexType, AttributeType attrType) |
| | | private static MatchingRule getMatchingRule(IndexType indexType, AttributeType attrType) |
| | | { |
| | | switch (indexType) |
| | | { |
| | |
| | | } |
| | | } |
| | | |
| | | private Index newAttributeIndex(LocalDBIndexCfg indexConfig, org.forgerock.opendj.ldap.spi.Indexer indexer) |
| | | private static Index newAttributeIndex(EntryContainer entryContainer, AttributeType attributeType, |
| | | org.forgerock.opendj.ldap.spi.Indexer indexer, int indexEntryLimit) |
| | | { |
| | | final AttributeType attrType = indexConfig.getAttribute(); |
| | | final String indexName = getIndexName(attrType, indexer.getIndexID()); |
| | | final AttributeIndexer attrIndexer = new AttributeIndexer(attrType, indexer); |
| | | return entryContainer.newIndexForAttribute(indexName, attrIndexer, indexConfig.getIndexEntryLimit()); |
| | | final String indexName = getIndexName(entryContainer, attributeType, indexer.getIndexID()); |
| | | final AttributeIndexer attrIndexer = new AttributeIndexer(attributeType, indexer); |
| | | return entryContainer.newIndexForAttribute(indexName, attrIndexer, indexEntryLimit); |
| | | } |
| | | |
| | | private String getIndexName(AttributeType attrType, String indexID) |
| | | private static String getIndexName(EntryContainer entryContainer, AttributeType attrType, String indexID) |
| | | { |
| | | return entryContainer.getDatabasePrefix() + "_" + attrType.getNameOrOID() + "." + indexID; |
| | | } |
| | |
| | | */ |
| | | public void open() throws DatabaseException |
| | | { |
| | | for (Index index : nameToIndexes.values()) |
| | | for (Index index : indexIdToIndexes.values()) |
| | | { |
| | | index.open(); |
| | | } |
| | |
| | | @Override |
| | | public void close() |
| | | { |
| | | Utils.closeSilently(nameToIndexes.values()); |
| | | Utils.closeSilently(indexIdToIndexes.values()); |
| | | indexConfig.removeChangeListener(this); |
| | | // The entryContainer is responsible for closing the JE databases. |
| | | } |
| | |
| | | * @throws DatabaseException If an error occurs in the JE database. |
| | | * @throws DirectoryException If a Directory Server error occurs. |
| | | */ |
| | | public void addEntry(IndexBuffer buffer, EntryID entryID, Entry entry) |
| | | throws DatabaseException, DirectoryException |
| | | public void addEntry(IndexBuffer buffer, EntryID entryID, Entry entry) throws DatabaseException, DirectoryException |
| | | { |
| | | final IndexingOptions options = indexQueryFactory.getIndexingOptions(); |
| | | for (Index index : nameToIndexes.values()) |
| | | for (Index index : indexIdToIndexes.values()) |
| | | { |
| | | index.addEntry(buffer, entryID, entry, options); |
| | | index.addEntry(buffer, entryID, entry); |
| | | } |
| | | } |
| | | |
| | |
| | | public void removeEntry(IndexBuffer buffer, EntryID entryID, Entry entry) |
| | | throws DatabaseException, DirectoryException |
| | | { |
| | | final IndexingOptions options = indexQueryFactory.getIndexingOptions(); |
| | | for (Index index : nameToIndexes.values()) |
| | | for (Index index : indexIdToIndexes.values()) |
| | | { |
| | | index.removeEntry(buffer, entryID, entry, options); |
| | | index.removeEntry(buffer, entryID, entry); |
| | | } |
| | | } |
| | | |
| | |
| | | List<Modification> mods) |
| | | throws DatabaseException |
| | | { |
| | | final IndexingOptions options = indexQueryFactory.getIndexingOptions(); |
| | | for (Index index : nameToIndexes.values()) |
| | | for (Index index : indexIdToIndexes.values()) |
| | | { |
| | | index.modifyEntry(buffer, entryID, oldEntry, newEntry, mods, options); |
| | | index.modifyEntry(buffer, entryID, oldEntry, newEntry, mods); |
| | | } |
| | | } |
| | | |
| | |
| | | * @param len The length of the substring. |
| | | * @return A byte string containing a substring key. |
| | | */ |
| | | private ByteString makeSubstringKey(byte[] bytes, int pos, int len) |
| | | private static ByteString makeSubstringKey(byte[] bytes, int pos, int len) |
| | | { |
| | | byte[] keyBytes = new byte[len]; |
| | | System.arraycopy(bytes, pos, keyBytes, 0, len); |
| | |
| | | { |
| | | long entryLimitExceededCount = 0; |
| | | |
| | | for (Index index : nameToIndexes.values()) |
| | | for (Index index : indexIdToIndexes.values()) |
| | | { |
| | | entryLimitExceededCount += index.getEntryLimitExceededCount(); |
| | | } |
| | |
| | | */ |
| | | public void listDatabases(List<DatabaseContainer> dbList) |
| | | { |
| | | dbList.addAll(nameToIndexes.values()); |
| | | dbList.addAll(indexIdToIndexes.values()); |
| | | } |
| | | |
| | | /** |
| | |
| | | return true; |
| | | } |
| | | |
| | | private boolean isIndexAcceptable(LocalDBIndexCfg cfg, IndexType indexType, |
| | | private static boolean isIndexAcceptable(LocalDBIndexCfg cfg, IndexType indexType, |
| | | List<LocalizableMessage> unacceptableReasons) |
| | | { |
| | | final String indexId = indexType.toString(); |
| | | final AttributeType attrType = cfg.getAttribute(); |
| | | if (cfg.getIndexType().contains(indexType) |
| | | && nameToIndexes.get(indexId) == null |
| | | && getMatchingRule(indexType, attrType) == null) |
| | | { |
| | | unacceptableReasons.add(ERR_CONFIG_INDEX_TYPE_NEEDS_MATCHING_RULE.get(attrType, indexId)); |
| | | unacceptableReasons.add(ERR_CONFIG_INDEX_TYPE_NEEDS_MATCHING_RULE.get(attrType, indexType.toString())); |
| | | return false; |
| | | } |
| | | return true; |
| | |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public synchronized ConfigChangeResult applyConfigurationChange(LocalDBIndexCfg cfg) |
| | | public synchronized ConfigChangeResult applyConfigurationChange(final LocalDBIndexCfg newConfiguration) |
| | | { |
| | | final ConfigChangeResult ccr = new ConfigChangeResult(); |
| | | final IndexingOptions newIndexingOptions = new JEIndexingOptions(newConfiguration.getSubstringLength()); |
| | | try |
| | | { |
| | | applyChangeToPresenceIndex(cfg, ccr); |
| | | applyChangeToIndex(IndexType.EQUALITY, cfg, ccr); |
| | | applyChangeToIndex(IndexType.SUBSTRING, cfg, ccr); |
| | | applyChangeToIndex(IndexType.ORDERING, cfg, ccr); |
| | | applyChangeToIndex(IndexType.APPROXIMATE, cfg, ccr); |
| | | applyChangeToExtensibleIndexes(cfg, ccr); |
| | | Map<String, Index> newIndexIdToIndexes = buildIndexes(entryContainer, newConfiguration, newIndexingOptions); |
| | | |
| | | extensibleIndexesMapping = computeExtensibleIndexesMapping(); |
| | | indexConfig = cfg; |
| | | final Map<String, Index> removedIndexes = new HashMap<>(indexIdToIndexes); |
| | | removedIndexes.keySet().removeAll(newIndexIdToIndexes.keySet()); |
| | | |
| | | return ccr; |
| | | final Map<String, Index> addedIndexes = new HashMap<>(newIndexIdToIndexes); |
| | | addedIndexes.keySet().removeAll(indexIdToIndexes.keySet()); |
| | | |
| | | final Map<String, Index> updatedIndexes = new HashMap<>(indexIdToIndexes); |
| | | updatedIndexes.keySet().retainAll(newIndexIdToIndexes.keySet()); |
| | | |
| | | // Replace instances of Index created by buildIndexes() with the one already opened and present in the actual |
| | | // indexIdToIndexes |
| | | newIndexIdToIndexes.putAll(updatedIndexes); |
| | | |
| | | // Open added indexes *before* adding them to indexIdToIndexes |
| | | for (Index addedIndex : addedIndexes.values()) |
| | | { |
| | | openIndex(addedIndex, ccr); |
| | | } |
| | | |
| | | indexConfig = newConfiguration; |
| | | indexingOptions = newIndexingOptions; |
| | | indexIdToIndexes = Collections.unmodifiableMap(newIndexIdToIndexes); |
| | | indexQueryFactory = new IndexQueryFactoryImpl(indexIdToIndexes, indexingOptions, indexConfig.getAttribute()); |
| | | |
| | | // FIXME: There is no guarantee here that deleted index are not currently involved in a query |
| | | for (Index removedIndex : removedIndexes.values()) |
| | | { |
| | | deleteIndex(entryContainer, removedIndex); |
| | | } |
| | | |
| | | for (Index updatedIndex : updatedIndexes.values()) |
| | | { |
| | | updateIndex(updatedIndex, newConfiguration.getIndexEntryLimit(), ccr); |
| | | } |
| | | } |
| | | catch(Exception e) |
| | | catch (Exception e) |
| | | { |
| | | ccr.setResultCode(DirectoryServer.getServerErrorResultCode()); |
| | | ccr.addMessage(LocalizableMessage.raw(StaticUtils.stackTraceToSingleLineString(e))); |
| | | return ccr; |
| | | } |
| | | |
| | | return ccr; |
| | | } |
| | | |
| | | private void applyChangeToExtensibleIndexes(LocalDBIndexCfg cfg, final ConfigChangeResult ccr) |
| | | { |
| | | final AttributeType attrType = cfg.getAttribute(); |
| | | if (!cfg.getIndexType().contains(IndexType.EXTENSIBLE)) |
| | | { |
| | | final Set<MatchingRule> validRules = Collections.emptySet(); |
| | | final Set<String> validIndexIds = Collections.emptySet(); |
| | | removeIndexesForExtensibleMatchingRules(validRules, validIndexIds); |
| | | return; |
| | | } |
| | | |
| | | final Set<String> extensibleRules = cfg.getIndexExtensibleMatchingRule(); |
| | | final Set<MatchingRule> validRules = new HashSet<MatchingRule>(); |
| | | final Set<String> validIndexIds = new HashSet<String>(); |
| | | final int indexEntryLimit = cfg.getIndexEntryLimit(); |
| | | |
| | | for (String ruleName : extensibleRules) |
| | | { |
| | | MatchingRule rule = DirectoryServer.getMatchingRule(toLowerCase(ruleName)); |
| | | if (rule == null) |
| | | { |
| | | logger.error(ERR_CONFIG_INDEX_TYPE_NEEDS_VALID_MATCHING_RULE, attrType, ruleName); |
| | | continue; |
| | | } |
| | | validRules.add(rule); |
| | | for (org.forgerock.opendj.ldap.spi.Indexer indexer : rule.getIndexers()) |
| | | { |
| | | String indexId = indexer.getIndexID(); |
| | | validIndexIds.add(indexId); |
| | | if (!nameToIndexes.containsKey(indexId)) |
| | | { |
| | | Index index = newAttributeIndex(cfg, indexer); |
| | | openIndex(index, ccr); |
| | | nameToIndexes.put(indexId, index); |
| | | } |
| | | else |
| | | { |
| | | Index index = nameToIndexes.get(indexId); |
| | | if (index.setIndexEntryLimit(indexEntryLimit)) |
| | | { |
| | | ccr.setAdminActionRequired(true); |
| | | ccr.addMessage(NOTE_CONFIG_INDEX_ENTRY_LIMIT_REQUIRES_REBUILD.get(index.getName())); |
| | | } |
| | | if (indexConfig.getSubstringLength() != cfg.getSubstringLength()) |
| | | { |
| | | index.setIndexer(new AttributeIndexer(attrType, indexer)); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | removeIndexesForExtensibleMatchingRules(validRules, validIndexIds); |
| | | } |
| | | |
| | | /** Remove indexes which do not correspond to valid rules. */ |
| | | private void removeIndexesForExtensibleMatchingRules(Set<MatchingRule> validRules, Set<String> validIndexIds) |
| | | { |
| | | final Set<MatchingRule> rulesToDelete = getCurrentExtensibleMatchingRules(); |
| | | rulesToDelete.removeAll(validRules); |
| | | if (!rulesToDelete.isEmpty()) |
| | | { |
| | | entryContainer.exclusiveLock.lock(); |
| | | try |
| | | { |
| | | for (MatchingRule rule: rulesToDelete) |
| | | { |
| | | final List<String> indexIdsToRemove = new ArrayList<String>(); |
| | | for (org.forgerock.opendj.ldap.spi.Indexer indexer : rule.getIndexers()) |
| | | { |
| | | final String indexId = indexer.getIndexID(); |
| | | if (!validIndexIds.contains(indexId)) |
| | | { |
| | | indexIdsToRemove.add(indexId); |
| | | } |
| | | } |
| | | // Delete indexes which are not used |
| | | for (String indexId : indexIdsToRemove) |
| | | { |
| | | Index index = nameToIndexes.get(indexId); |
| | | if (index != null) |
| | | { |
| | | entryContainer.deleteDatabase(index); |
| | | nameToIndexes.remove(index); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | entryContainer.exclusiveLock.unlock(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | private Set<MatchingRule> getCurrentExtensibleMatchingRules() |
| | | { |
| | | final Set<MatchingRule> rules = new HashSet<MatchingRule>(); |
| | | for (String ruleName : indexConfig.getIndexExtensibleMatchingRule()) |
| | | { |
| | | final MatchingRule rule = DirectoryServer.getMatchingRule(toLowerCase(ruleName)); |
| | | if (rule != null) |
| | | { |
| | | rules.add(rule); |
| | | } |
| | | } |
| | | return rules; |
| | | } |
| | | |
| | | private void applyChangeToIndex(IndexType indexType, LocalDBIndexCfg cfg, final ConfigChangeResult ccr) |
| | | { |
| | | String indexId = indexType.toString(); |
| | | Index index = nameToIndexes.get(indexId); |
| | | if (!cfg.getIndexType().contains(indexType)) |
| | | { |
| | | removeIndex(index, indexType); |
| | | return; |
| | | } |
| | | |
| | | if (index == null) |
| | | { |
| | | final MatchingRule matchingRule = getMatchingRule(indexType, cfg.getAttribute()); |
| | | for (org.forgerock.opendj.ldap.spi.Indexer indexer : matchingRule.getIndexers()) |
| | | { |
| | | index = newAttributeIndex(cfg, indexer); |
| | | openIndex(index, ccr); |
| | | nameToIndexes.put(indexId, index); |
| | | } |
| | | } |
| | | else |
| | | { |
| | | // already exists. Just update index entry limit. |
| | | if (index.setIndexEntryLimit(cfg.getIndexEntryLimit())) |
| | | { |
| | | ccr.setAdminActionRequired(true); |
| | | ccr.addMessage(NOTE_CONFIG_INDEX_ENTRY_LIMIT_REQUIRES_REBUILD.get(index.getName())); |
| | | } |
| | | } |
| | | } |
| | | |
| | | private void applyChangeToPresenceIndex(LocalDBIndexCfg cfg, final ConfigChangeResult ccr) |
| | | { |
| | | final IndexType indexType = IndexType.PRESENCE; |
| | | final String indexID = indexType.toString(); |
| | | Index index = nameToIndexes.get(indexID); |
| | | if (!cfg.getIndexType().contains(indexType)) |
| | | { |
| | | removeIndex(index, indexType); |
| | | return; |
| | | } |
| | | |
| | | if (index == null) |
| | | { |
| | | index = newPresenceIndex(cfg); |
| | | openIndex(index, ccr); |
| | | nameToIndexes.put(indexID, index); |
| | | } |
| | | else |
| | | { |
| | | // already exists. Just update index entry limit. |
| | | if (index.setIndexEntryLimit(cfg.getIndexEntryLimit())) |
| | | { |
| | | ccr.setAdminActionRequired(true); |
| | | ccr.addMessage(NOTE_CONFIG_INDEX_ENTRY_LIMIT_REQUIRES_REBUILD.get(index.getName())); |
| | | } |
| | | } |
| | | } |
| | | |
| | | private void removeIndex(Index index, IndexType indexType) |
| | | { |
| | | if (index != null) |
| | | { |
| | | entryContainer.exclusiveLock.lock(); |
| | | try |
| | | { |
| | | nameToIndexes.remove(indexType.toString()); |
| | | entryContainer.deleteDatabase(index); |
| | | } |
| | | finally |
| | | { |
| | | entryContainer.exclusiveLock.unlock(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | private void openIndex(Index index, final ConfigChangeResult ccr) |
| | | private static void openIndex(Index index, ConfigChangeResult ccr) |
| | | { |
| | | index.open(); |
| | | |
| | | if (!index.isTrusted()) |
| | | { |
| | | ccr.setAdminActionRequired(true); |
| | |
| | | } |
| | | } |
| | | |
| | | private static void updateIndex(Index updatedIndex, int newIndexEntryLimit, ConfigChangeResult ccr) |
| | | { |
| | | if (updatedIndex.setIndexEntryLimit(newIndexEntryLimit)) |
| | | { |
| | | // This index can still be used since index size limit doesn't impact validity of the results. |
| | | ccr.setAdminActionRequired(true); |
| | | ccr.addMessage(NOTE_CONFIG_INDEX_ENTRY_LIMIT_REQUIRES_REBUILD.get(updatedIndex.getName())); |
| | | } |
| | | } |
| | | |
| | | private static void deleteIndex(EntryContainer entryContainer, Index index) |
| | | { |
| | | entryContainer.exclusiveLock.lock(); |
| | | try |
| | | { |
| | | entryContainer.deleteDatabase(index); |
| | | } |
| | | finally |
| | | { |
| | | entryContainer.exclusiveLock.unlock(); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Return true iff this index is trusted. |
| | | * @return the trusted state of this index |
| | | */ |
| | | public boolean isTrusted() |
| | | { |
| | | for (Index index : nameToIndexes.values()) |
| | | for (Index index : indexIdToIndexes.values()) |
| | | { |
| | | if (!index.isTrusted()) |
| | | { |
| | |
| | | + indexConfig.getAttribute().getNameOrOID(); |
| | | } |
| | | |
| | | /** |
| | | * Return the equality index. |
| | | * |
| | | * @return The equality index. |
| | | */ |
| | | public Index getEqualityIndex() { |
| | | return nameToIndexes.get(IndexType.EQUALITY.toString()); |
| | | } |
| | | |
| | | /** |
| | | * Return the approximate index. |
| | | * |
| | | * @return The approximate index. |
| | | */ |
| | | public Index getApproximateIndex() { |
| | | return nameToIndexes.get(IndexType.APPROXIMATE.toString()); |
| | | } |
| | | |
| | | /** |
| | | * Return the ordering index. |
| | | * |
| | | * @return The ordering index. |
| | | */ |
| | | public Index getOrderingIndex() { |
| | | return nameToIndexes.get(IndexType.ORDERING.toString()); |
| | | } |
| | | |
| | | /** |
| | | * Return the substring index. |
| | | * |
| | | * @return The substring index. |
| | | */ |
| | | public Index getSubstringIndex() { |
| | | return nameToIndexes.get(IndexType.SUBSTRING.toString()); |
| | | } |
| | | |
| | | /** |
| | | * Return the presence index. |
| | | * |
| | | * @return The presence index. |
| | | */ |
| | | public Index getPresenceIndex() { |
| | | return nameToIndexes.get(IndexType.PRESENCE.toString()); |
| | | } |
| | | |
| | | /** |
| | | * Return the mapping of extensible index types and indexes. |
| | | * |
| | | * @return The map containing entries (extensible index type, list of indexes) |
| | | */ |
| | | public Map<String, Collection<Index>> getExtensibleIndexes() |
| | | { |
| | | return extensibleIndexesMapping; |
| | | } |
| | | |
| | | private Map<String, Collection<Index>> computeExtensibleIndexesMapping() |
| | | { |
| | | final Collection<Index> substring = new ArrayList<Index>(); |
| | | final Collection<Index> shared = new ArrayList<Index>(); |
| | | for (Map.Entry<String, Index> entry : nameToIndexes.entrySet()) |
| | | { |
| | | final String indexId = entry.getKey(); |
| | | if (isDefaultIndex(indexId)) { |
| | | continue; |
| | | } |
| | | if (indexId.endsWith(EXTENSIBLE_INDEXER_ID_SUBSTRING)) |
| | | { |
| | | substring.add(entry.getValue()); |
| | | } |
| | | else |
| | | { |
| | | shared.add(entry.getValue()); |
| | | } |
| | | } |
| | | final Map<String, Collection<Index>> indexMap = new HashMap<String,Collection<Index>>(); |
| | | indexMap.put(EXTENSIBLE_INDEXER_ID_SUBSTRING, substring); |
| | | indexMap.put(EXTENSIBLE_INDEXER_ID_SHARED, shared); |
| | | return Collections.unmodifiableMap(indexMap); |
| | | } |
| | | |
| | | private boolean isDefaultIndex(String indexId) |
| | | { |
| | | return indexId.equals(IndexType.EQUALITY.toString()) |
| | | || indexId.equals(IndexType.PRESENCE.toString()) |
| | | || indexId.equals(IndexType.SUBSTRING.toString()) |
| | | || indexId.equals(IndexType.ORDERING.toString()) |
| | | || indexId.equals(IndexType.APPROXIMATE.toString()); |
| | | Index getIndex(String indexID) { |
| | | return indexIdToIndexes.get(indexID); |
| | | } |
| | | |
| | | /** |
| | | * Retrieves all the indexes used by this attribute index. |
| | | * |
| | | * @return A collection of all indexes in use by this attribute |
| | | * @return An immutable collection of all indexes in use by this attribute |
| | | * index. |
| | | */ |
| | | public Collection<Index> getAllIndexes() { |
| | | return new LinkedHashSet<Index>(nameToIndexes.values()); |
| | | return indexIdToIndexes.values(); |
| | | } |
| | | |
| | | /** |
| | |
| | | if (debugBuffer != null) |
| | | { |
| | | debugBuffer.append("[INDEX:"); |
| | | for (org.forgerock.opendj.ldap.spi.Indexer indexer : rule.getIndexers()) |
| | | for (org.forgerock.opendj.ldap.spi.Indexer indexer : rule.createIndexers(indexingOptions)) |
| | | { |
| | | debugBuffer.append(" ") |
| | | .append(filter.getAttributeType().getNameOrOID()) |
| | |
| | | |
| | | private boolean ruleHasAtLeasOneIndex(MatchingRule rule) |
| | | { |
| | | for (org.forgerock.opendj.ldap.spi.Indexer indexer : rule.getIndexers()) |
| | | for (org.forgerock.opendj.ldap.spi.Indexer indexer : rule.createIndexers(indexingOptions)) |
| | | { |
| | | if (nameToIndexes.containsKey(indexer.getIndexID())) |
| | | if (indexIdToIndexes.containsKey(indexer.getIndexID())) |
| | | { |
| | | return true; |
| | | } |
| | |
| | | } |
| | | |
| | | /** This class extends the IndexConfig for JE Backend. */ |
| | | private final class JEIndexConfig implements IndexingOptions |
| | | private static final class JEIndexingOptions implements IndexingOptions |
| | | { |
| | | /** The length of the substring index. */ |
| | | private int substringLength; |
| | |
| | | * Creates a new JEIndexConfig instance. |
| | | * @param substringLength The length of the substring. |
| | | */ |
| | | private JEIndexConfig(int substringLength) |
| | | private JEIndexingOptions(int substringLength) |
| | | { |
| | | this.substringLength = substringLength; |
| | | } |
| | |
| | | * |
| | | * |
| | | * Copyright 2009-2010 Sun Microsystems, Inc. |
| | | * Portions Copyright 2014 ForgeRock AS |
| | | * Portions Copyright 2014-2015 ForgeRock AS |
| | | */ |
| | | package org.opends.server.backends.jeb; |
| | | |
| | |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | | import org.forgerock.opendj.ldap.DecodeException; |
| | | import org.forgerock.opendj.ldap.schema.Schema; |
| | | import org.forgerock.opendj.ldap.spi.IndexingOptions; |
| | | import org.opends.server.types.Attribute; |
| | | import org.opends.server.types.AttributeType; |
| | | import org.opends.server.types.Entry; |
| | |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public void indexEntry(Entry entry, Set<ByteString> keys, IndexingOptions options) |
| | | public void indexEntry(Entry entry, Set<ByteString> keys) |
| | | { |
| | | List<Attribute> attrList = entry.getAttribute(attributeType); |
| | | final List<Attribute> attrList = entry.getAttribute(attributeType); |
| | | if (attrList != null) |
| | | { |
| | | indexAttribute(attrList, keys, options); |
| | | indexAttribute(attrList, keys); |
| | | } |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public void modifyEntry(Entry oldEntry, Entry newEntry, |
| | | List<Modification> mods, Map<ByteString, Boolean> modifiedKeys, |
| | | IndexingOptions options) |
| | | List<Modification> mods, Map<ByteString, Boolean> modifiedKeys) |
| | | { |
| | | List<Attribute> newAttributes = newEntry.getAttribute(attributeType, true); |
| | | List<Attribute> oldAttributes = oldEntry.getAttribute(attributeType, true); |
| | | |
| | | indexAttribute(oldAttributes, modifiedKeys, false, options); |
| | | indexAttribute(newAttributes, modifiedKeys, true, options); |
| | | indexAttribute(oldAttributes, modifiedKeys, false); |
| | | indexAttribute(newAttributes, modifiedKeys, true); |
| | | } |
| | | |
| | | |
| | |
| | | * @param attrList The attribute for which substring keys are required. |
| | | * @param keys The set into which the generated keys will be inserted. |
| | | */ |
| | | private void indexAttribute(List<Attribute> attrList, Set<ByteString> keys, |
| | | IndexingOptions options) |
| | | private void indexAttribute(List<Attribute> attrList, Set<ByteString> keys) |
| | | { |
| | | if (attrList == null) |
| | | { |
| | |
| | | { |
| | | try |
| | | { |
| | | indexer.createKeys(Schema.getDefaultSchema(), value, options, keys); |
| | | indexer.createKeys(Schema.getDefaultSchema(), value, keys); |
| | | } |
| | | catch (DecodeException e) |
| | | { |
| | |
| | | * @param insert <code>true</code> if generated keys should |
| | | * be inserted or <code>false</code> otherwise. |
| | | */ |
| | | private void indexAttribute(List<Attribute> attrList, |
| | | Map<ByteString, Boolean> modifiedKeys, Boolean insert, |
| | | IndexingOptions options) |
| | | private void indexAttribute(List<Attribute> attrList, Map<ByteString, Boolean> modifiedKeys, Boolean insert) |
| | | { |
| | | if (attrList == null) |
| | | { |
| | | return; |
| | | } |
| | | |
| | | final Set<ByteString> keys = new HashSet<ByteString>(); |
| | | indexAttribute(attrList, keys, options); |
| | | final Set<ByteString> keys = new HashSet<>(); |
| | | indexAttribute(attrList, keys); |
| | | computeModifiedKeys(modifiedKeys, insert, keys); |
| | | } |
| | | |
| | |
| | | * |
| | | * |
| | | * Copyright 2006-2010 Sun Microsystems, Inc. |
| | | * Portions Copyright 2014 ForgeRock AS |
| | | * Portions Copyright 2014-2015 ForgeRock AS |
| | | */ |
| | | package org.opends.server.backends.jeb; |
| | | |
| | |
| | | import org.forgerock.opendj.ldap.schema.MatchingRule; |
| | | import org.forgerock.opendj.ldap.schema.Schema; |
| | | import org.forgerock.opendj.ldap.spi.Indexer; |
| | | import org.forgerock.opendj.ldap.spi.IndexingOptions; |
| | | import org.opends.server.types.AttributeType; |
| | | |
| | | /** |
| | |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public void createKeys(Schema schema, ByteSequence value, |
| | | IndexingOptions options, Collection<ByteString> keys) |
| | | throws DecodeException |
| | | public void createKeys(Schema schema, ByteSequence value, Collection<ByteString> keys) throws DecodeException |
| | | { |
| | | keys.add(equalityRule.normalizeAttributeValue(value)); |
| | | } |
| | |
| | | * |
| | | * |
| | | * Copyright 2006-2008 Sun Microsystems, Inc. |
| | | * Portions Copyright 2014 ForgeRock AS |
| | | * Portions Copyright 2014-2015 ForgeRock AS |
| | | */ |
| | | package org.opends.server.backends.jeb; |
| | | |
| | | import java.util.*; |
| | | |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | | import org.forgerock.opendj.ldap.spi.IndexingOptions; |
| | | import org.opends.server.types.Entry; |
| | | import org.opends.server.types.Modification; |
| | | |
| | |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public void indexEntry(Entry entry, Set<ByteString> addKeys, IndexingOptions options) |
| | | public void indexEntry(Entry entry, Set<ByteString> addKeys) |
| | | { |
| | | // The superior entry IDs are in the entry attachment. |
| | | ArrayList<EntryID> ids = (ArrayList<EntryID>) entry.getAttachment(); |
| | |
| | | @Override |
| | | public void modifyEntry(Entry oldEntry, Entry newEntry, |
| | | List<Modification> mods, |
| | | Map<ByteString, Boolean> modifiedKeys, IndexingOptions options) |
| | | Map<ByteString, Boolean> modifiedKeys) |
| | | { |
| | | // Nothing to do. |
| | | } |
| | |
| | | * |
| | | * |
| | | * Copyright 2006-2008 Sun Microsystems, Inc. |
| | | * Portions Copyright 2014 ForgeRock AS |
| | | * Portions Copyright 2014-2015 ForgeRock AS |
| | | */ |
| | | package org.opends.server.backends.jeb; |
| | | |
| | | import java.util.*; |
| | | |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | | import org.forgerock.opendj.ldap.spi.IndexingOptions; |
| | | import org.opends.server.types.Entry; |
| | | import org.opends.server.types.Modification; |
| | | |
| | |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public void indexEntry(Entry entry, Set<ByteString> addKeys, IndexingOptions options) |
| | | public void indexEntry(Entry entry, Set<ByteString> addKeys) |
| | | { |
| | | // The superior entry IDs are in the entry attachment. |
| | | ArrayList<EntryID> ids = (ArrayList<EntryID>) entry.getAttachment(); |
| | |
| | | @Override |
| | | public void modifyEntry(Entry oldEntry, Entry newEntry, |
| | | List<Modification> mods, |
| | | Map<ByteString, Boolean> modifiedKeys, IndexingOptions options) |
| | | Map<ByteString, Boolean> modifiedKeys) |
| | | { |
| | | // Nothing to do. |
| | | } |
| | |
| | | import org.forgerock.opendj.config.server.ConfigException; |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | | import org.forgerock.opendj.ldap.ResultCode; |
| | | import org.forgerock.opendj.ldap.spi.IndexingOptions; |
| | | import org.forgerock.util.Utils; |
| | | import org.opends.server.admin.std.meta.LocalDBIndexCfgDefn.IndexType; |
| | | import org.opends.server.admin.std.server.LocalDBBackendCfg; |
| | |
| | | { |
| | | for (AttributeIndex attributeIndex : suffix.getAttrIndexMap().values()) |
| | | { |
| | | putInIdContainerMap(attributeIndex.getEqualityIndex()); |
| | | putInIdContainerMap(attributeIndex.getPresenceIndex()); |
| | | putInIdContainerMap(attributeIndex.getSubstringIndex()); |
| | | putInIdContainerMap(attributeIndex.getOrderingIndex()); |
| | | putInIdContainerMap(attributeIndex.getApproximateIndex()); |
| | | Map<String, Collection<Index>> extensibleMap = attributeIndex.getExtensibleIndexes(); |
| | | if (!extensibleMap.isEmpty()) |
| | | { |
| | | putInIdContainerMap(extensibleMap.get(EXTENSIBLE_INDEXER_ID_SUBSTRING)); |
| | | putInIdContainerMap(extensibleMap.get(EXTENSIBLE_INDEXER_ID_SHARED)); |
| | | } |
| | | } |
| | | } |
| | | |
| | | private void putInIdContainerMap(Collection<Index> indexes) |
| | | { |
| | | if (indexes != null) |
| | | { |
| | | for (Index index : indexes) |
| | | { |
| | | for(Index index : attributeIndex.getAllIndexes()) { |
| | | putInIdContainerMap(index); |
| | | } |
| | | } |
| | |
| | | } |
| | | |
| | | @Override |
| | | void processAttribute(Index index, Entry entry, EntryID entryID, IndexingOptions options, |
| | | IndexKey indexKey) throws DatabaseException, InterruptedException |
| | | void processAttribute(Index index, Entry entry, EntryID entryID, IndexKey indexKey) |
| | | throws DatabaseException, InterruptedException |
| | | { |
| | | if (oldEntry != null) |
| | | { |
| | | deleteKeySet.clear(); |
| | | index.indexEntry(oldEntry, deleteKeySet, options); |
| | | index.indexEntry(oldEntry, deleteKeySet); |
| | | for (ByteString delKey : deleteKeySet) |
| | | { |
| | | processKey(index, delKey.toByteArray(), entryID, indexKey, false); |
| | | } |
| | | } |
| | | insertKeySet.clear(); |
| | | index.indexEntry(entry, insertKeySet, options); |
| | | index.indexEntry(entry, insertKeySet); |
| | | for (ByteString key : insertKeySet) |
| | | { |
| | | processKey(index, key.toByteArray(), entryID, indexKey, true); |
| | |
| | | private final Map<IndexKey, IndexOutputBuffer> indexBufferMap = new HashMap<IndexKey, IndexOutputBuffer>(); |
| | | private final Set<ByteString> insertKeySet = new HashSet<ByteString>(); |
| | | private final EntryInformation entryInfo = new EntryInformation(); |
| | | private final IndexKey dnIndexKey = new IndexKey(dnType, ImportIndexType.DN, 1); |
| | | private final IndexKey dnIndexKey = new IndexKey(dnType, ImportIndexType.DN.toString(), 1); |
| | | private DatabaseEntry keyEntry = new DatabaseEntry(); |
| | | private DatabaseEntry valEntry = new DatabaseEntry(); |
| | | |
| | |
| | | void fillIndexKey(Suffix suffix, AttributeIndex attrIndex, Entry entry, AttributeType attrType, EntryID entryID) |
| | | throws DatabaseException, InterruptedException, DirectoryException, JebException |
| | | { |
| | | final IndexingOptions options = attrIndex.getIndexingOptions(); |
| | | |
| | | processAttribute(attrIndex.getEqualityIndex(), ImportIndexType.EQUALITY, entry, attrType, entryID, options); |
| | | processAttribute(attrIndex.getPresenceIndex(), ImportIndexType.PRESENCE, entry, attrType, entryID, options); |
| | | processAttribute(attrIndex.getSubstringIndex(), ImportIndexType.SUBSTRING, entry, attrType, entryID, options); |
| | | processAttribute(attrIndex.getOrderingIndex(), ImportIndexType.ORDERING, entry, attrType, entryID, options); |
| | | processAttribute(attrIndex.getApproximateIndex(), ImportIndexType.APPROXIMATE, entry, attrType, entryID, options); |
| | | for(Index index : attrIndex.getAllIndexes()) { |
| | | processAttribute(index, entry, attrType, entryID); |
| | | } |
| | | |
| | | for (VLVIndex vlvIdx : suffix.getEntryContainer().getVLVIndexes()) |
| | | { |
| | | Transaction transaction = null; |
| | | vlvIdx.addEntry(transaction, entryID, entry); |
| | | } |
| | | Map<String, Collection<Index>> extensibleMap = attrIndex.getExtensibleIndexes(); |
| | | if (!extensibleMap.isEmpty()) |
| | | { |
| | | Collection<Index> subIndexes = extensibleMap.get(EXTENSIBLE_INDEXER_ID_SUBSTRING); |
| | | processAttributes(subIndexes, ImportIndexType.EX_SUBSTRING, entry, attrType, entryID, options); |
| | | Collection<Index> sharedIndexes = extensibleMap.get(EXTENSIBLE_INDEXER_ID_SHARED); |
| | | processAttributes(sharedIndexes, ImportIndexType.EX_SHARED, entry, attrType, entryID, options); |
| | | } |
| | | } |
| | | |
| | | private void processAttribute(Index index, ImportIndexType presence, Entry entry, |
| | | AttributeType attributeType, EntryID entryID, IndexingOptions options) throws InterruptedException |
| | | private void processAttribute(Index index, Entry entry, AttributeType attributeType, EntryID entryID) |
| | | throws InterruptedException |
| | | { |
| | | if (index != null) |
| | | { |
| | | IndexKey indexKey = new IndexKey(attributeType, presence, index.getIndexEntryLimit()); |
| | | processAttribute(index, entry, entryID, options, indexKey); |
| | | processAttribute(index, entry, entryID, |
| | | new IndexKey(attributeType, index.getName(), index.getIndexEntryLimit())); |
| | | } |
| | | } |
| | | |
| | | private void processAttributes(Collection<Index> indexes, ImportIndexType indexType, Entry entry, |
| | | AttributeType attributeType, EntryID entryID, IndexingOptions options) throws InterruptedException |
| | | private void processAttributes(Collection<Index> indexes, Entry entry, AttributeType attributeType, EntryID entryID) |
| | | throws InterruptedException |
| | | { |
| | | if (indexes != null) |
| | | { |
| | | for (Index index : indexes) |
| | | { |
| | | IndexKey indexKey = new IndexKey(attributeType, indexType, index.getIndexEntryLimit()); |
| | | processAttribute(index, entry, entryID, options, indexKey); |
| | | processAttribute(index, entry, entryID, |
| | | new IndexKey(attributeType, index.getName(), index.getIndexEntryLimit())); |
| | | } |
| | | } |
| | | } |
| | | |
| | | void processAttribute(Index index, Entry entry, EntryID entryID, IndexingOptions options, |
| | | IndexKey indexKey) throws DatabaseException, InterruptedException |
| | | void processAttribute(Index index, Entry entry, EntryID entryID, IndexKey indexKey) |
| | | throws DatabaseException, InterruptedException |
| | | { |
| | | insertKeySet.clear(); |
| | | index.indexEntry(entry, insertKeySet, options); |
| | | index.indexEntry(entry, insertKeySet); |
| | | for (ByteString key : insertKeySet) |
| | | { |
| | | processKey(index, key.toByteArray(), entryID, indexKey, true); |
| | |
| | | { |
| | | return; |
| | | } |
| | | boolean isDN2ID = ImportIndexType.DN.equals(indexKey.getIndexType()); |
| | | boolean isDN2ID = ImportIndexType.DN.toString().equals(indexKey.getIndexName()); |
| | | IndexManager indexMgr = new IndexManager(indexKey.getName(), isDN2ID, indexKey.getEntryLimit()); |
| | | if (isDN2ID) |
| | | { |
| | |
| | | final AttributeType attrType, final boolean onlyDegraded) |
| | | throws DatabaseException |
| | | { |
| | | fillIndexMap(attrType, attrIndex.getSubstringIndex(), ImportIndexType.SUBSTRING, onlyDegraded); |
| | | fillIndexMap(attrType, attrIndex.getOrderingIndex(), ImportIndexType.ORDERING, onlyDegraded); |
| | | fillIndexMap(attrType, attrIndex.getEqualityIndex(), ImportIndexType.EQUALITY, onlyDegraded); |
| | | fillIndexMap(attrType, attrIndex.getPresenceIndex(), ImportIndexType.PRESENCE, onlyDegraded); |
| | | fillIndexMap(attrType, attrIndex.getApproximateIndex(), ImportIndexType.APPROXIMATE, onlyDegraded); |
| | | |
| | | final Map<String, Collection<Index>> extensibleMap = attrIndex.getExtensibleIndexes(); |
| | | if (!extensibleMap.isEmpty()) |
| | | { |
| | | final Collection<Index> subIndexes = extensibleMap.get(EXTENSIBLE_INDEXER_ID_SUBSTRING); |
| | | fillIndexMap(attrType, subIndexes, ImportIndexType.EX_SUBSTRING, onlyDegraded); |
| | | final Collection<Index> sharedIndexes = extensibleMap.get(EXTENSIBLE_INDEXER_ID_SHARED); |
| | | fillIndexMap(attrType, sharedIndexes, ImportIndexType.EX_SHARED, onlyDegraded); |
| | | for(Index index : attrIndex.getAllIndexes()) { |
| | | fillIndexMap(attrType, index, onlyDegraded); |
| | | } |
| | | } |
| | | |
| | | private void fillIndexMap(final AttributeType attrType, final Collection<Index> indexes, |
| | | final ImportIndexType importIndexType, final boolean onlyDegraded) |
| | | { |
| | | if (indexes != null && !indexes.isEmpty()) |
| | | { |
| | | final List<Index> mutableCopy = new LinkedList<Index>(indexes); |
| | | for (final Iterator<Index> it = mutableCopy.iterator(); it.hasNext();) |
| | | { |
| | | final Index sharedIndex = it.next(); |
| | | if (!onlyDegraded || !sharedIndex.isTrusted()) |
| | | { |
| | | if (!rebuildConfig.isClearDegradedState() || sharedIndex.getRecordCount() == 0) |
| | | { |
| | | putInIdContainerMap(sharedIndex); |
| | | } |
| | | } |
| | | else |
| | | { |
| | | // This index is not a candidate for rebuilding. |
| | | it.remove(); |
| | | } |
| | | } |
| | | if (!mutableCopy.isEmpty()) |
| | | { |
| | | extensibleIndexMap.put(new IndexKey(attrType, importIndexType, 0), mutableCopy); |
| | | } |
| | | } |
| | | } |
| | | |
| | | private void fillIndexMap(final AttributeType attrType, final Index index, |
| | | final ImportIndexType importIndexType, final boolean onlyDegraded) |
| | | private void fillIndexMap(final AttributeType attrType, final Index index, final boolean onlyDegraded) |
| | | { |
| | | if (index != null |
| | | && (!onlyDegraded || !index.isTrusted()) |
| | | && (!rebuildConfig.isClearDegradedState() || index.getRecordCount() == 0)) |
| | | { |
| | | putInIdContainerMap(index); |
| | | final IndexKey key = new IndexKey(attrType, importIndexType, index.getIndexEntryLimit()); |
| | | final IndexKey key = new IndexKey(attrType, index.getName(), index.getIndexEntryLimit()); |
| | | indexMap.put(key, index); |
| | | } |
| | | } |
| | |
| | | AttributeType attrType = key.getAttributeType(); |
| | | if (entry.hasAttribute(attrType)) |
| | | { |
| | | AttributeIndex attributeIndex = entryContainer.getAttributeIndex(attrType); |
| | | IndexingOptions options = attributeIndex.getIndexingOptions(); |
| | | for (Index index : mapEntry.getValue()) |
| | | { |
| | | processAttribute(index, entry, entryID, options, key); |
| | | processAttribute(index, entry, entryID, key); |
| | | } |
| | | } |
| | | } |
| | |
| | | AttributeType attrType = key.getAttributeType(); |
| | | if (entry.hasAttribute(attrType)) |
| | | { |
| | | AttributeIndex attributeIndex = entryContainer.getAttributeIndex(attrType); |
| | | IndexingOptions options = attributeIndex.getIndexingOptions(); |
| | | Index index = mapEntry.getValue(); |
| | | processAttribute(index, entry, entryID, options, key); |
| | | processAttribute(mapEntry.getValue(), entry, entryID, key); |
| | | } |
| | | } |
| | | } |
| | |
| | | { |
| | | |
| | | private final AttributeType attributeType; |
| | | private final ImportIndexType indexType; |
| | | private final String indexName; |
| | | private final int entryLimit; |
| | | |
| | | /** |
| | |
| | | * @param entryLimit |
| | | * The entry limit for the index. |
| | | */ |
| | | private IndexKey(AttributeType attributeType, ImportIndexType indexType, int entryLimit) |
| | | private IndexKey(AttributeType attributeType, String indexName, int entryLimit) |
| | | { |
| | | this.attributeType = attributeType; |
| | | this.indexType = indexType; |
| | | this.indexName = indexName; |
| | | this.entryLimit = entryLimit; |
| | | } |
| | | |
| | |
| | | { |
| | | IndexKey oKey = (IndexKey) obj; |
| | | if (attributeType.equals(oKey.getAttributeType()) |
| | | && indexType.equals(oKey.getIndexType())) |
| | | && indexName.equals(oKey.indexName)) |
| | | { |
| | | return true; |
| | | } |
| | |
| | | @Override |
| | | public int hashCode() |
| | | { |
| | | return attributeType.hashCode() + indexType.hashCode(); |
| | | return attributeType.hashCode() + indexName.hashCode(); |
| | | } |
| | | |
| | | /** |
| | |
| | | * |
| | | * @return The index type. |
| | | */ |
| | | public ImportIndexType getIndexType() |
| | | public String getIndexName() |
| | | { |
| | | return indexType; |
| | | return indexName; |
| | | } |
| | | |
| | | /** |
| | |
| | | public String getName() |
| | | { |
| | | return attributeType.getPrimaryName() + "." |
| | | + StaticUtils.toLowerCase(indexType.name()); |
| | | + StaticUtils.toLowerCase(indexName); |
| | | } |
| | | |
| | | /** |
| | |
| | | public String toString() |
| | | { |
| | | return getClass().getSimpleName() |
| | | + "(index=" + attributeType.getNameOrOID() + "." + indexType |
| | | + "(index=" + attributeType.getNameOrOID() + "." + indexName |
| | | + ", entryLimit=" + entryLimit |
| | | + ")"; |
| | | } |
| | |
| | | import org.forgerock.i18n.slf4j.LocalizedLogger; |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | | import org.forgerock.opendj.ldap.ConditionResult; |
| | | import org.forgerock.opendj.ldap.spi.IndexingOptions; |
| | | import org.opends.server.backends.jeb.IndexBuffer.BufferedIndexValues; |
| | | import org.opends.server.types.DirectoryException; |
| | | import org.opends.server.types.Entry; |
| | |
| | | } |
| | | } |
| | | |
| | | void indexEntry(Entry entry, Set<ByteString> keys, IndexingOptions options) |
| | | void indexEntry(Entry entry, Set<ByteString> keys) |
| | | { |
| | | indexer.indexEntry(entry, keys, options); |
| | | indexer.indexEntry(entry, keys); |
| | | } |
| | | |
| | | /** |
| | |
| | | * @param buffer The index buffer to use to store the deleted keys |
| | | * @param entryID The entry ID. |
| | | * @param entry The entry to be indexed. |
| | | * @param options The indexing options to use |
| | | * @throws DatabaseException If an error occurs in the JE database. |
| | | * @throws DirectoryException If a Directory Server error occurs. |
| | | */ |
| | | public void addEntry(IndexBuffer buffer, EntryID entryID, Entry entry, |
| | | IndexingOptions options) throws DatabaseException, DirectoryException |
| | | public void addEntry(IndexBuffer buffer, EntryID entryID, Entry entry) throws DatabaseException, DirectoryException |
| | | { |
| | | HashSet<ByteString> addKeys = new HashSet<ByteString>(); |
| | | indexer.indexEntry(entry, addKeys, options); |
| | | final Set<ByteString> addKeys = new HashSet<>(); |
| | | indexer.indexEntry(entry, addKeys); |
| | | |
| | | for (ByteString keyBytes : addKeys) |
| | | { |
| | |
| | | * @param buffer The index buffer to use to store the deleted keys |
| | | * @param entryID The entry ID |
| | | * @param entry The contents of the deleted entry. |
| | | * @param options The indexing options to use |
| | | * @throws DatabaseException If an error occurs in the JE database. |
| | | * @throws DirectoryException If a Directory Server error occurs. |
| | | */ |
| | | public void removeEntry(IndexBuffer buffer, EntryID entryID, Entry entry, |
| | | IndexingOptions options) throws DatabaseException, DirectoryException |
| | | public void removeEntry(IndexBuffer buffer, EntryID entryID, Entry entry) |
| | | throws DatabaseException, DirectoryException |
| | | { |
| | | HashSet<ByteString> delKeys = new HashSet<ByteString>(); |
| | | indexer.indexEntry(entry, delKeys, options); |
| | | final Set<ByteString> delKeys = new HashSet<>(); |
| | | indexer.indexEntry(entry, delKeys); |
| | | |
| | | for (ByteString keyBytes : delKeys) |
| | | { |
| | |
| | | * @param oldEntry The entry before the modifications were applied. |
| | | * @param newEntry The entry after the modifications were applied. |
| | | * @param mods The sequence of modifications in the Modify operation. |
| | | * @param options The indexing options to use |
| | | * @throws DatabaseException If an error occurs in the JE database. |
| | | */ |
| | | public void modifyEntry(IndexBuffer buffer, |
| | | EntryID entryID, |
| | | Entry oldEntry, |
| | | Entry newEntry, |
| | | List<Modification> mods, IndexingOptions options) |
| | | List<Modification> mods) |
| | | throws DatabaseException |
| | | { |
| | | TreeMap<ByteString, Boolean> modifiedKeys = |
| | | new TreeMap<ByteString, Boolean>(indexer.getBSComparator()); |
| | | indexer.modifyEntry(oldEntry, newEntry, mods, modifiedKeys, options); |
| | | final Map<ByteString, Boolean> modifiedKeys = new TreeMap<ByteString, Boolean>(indexer.getBSComparator()); |
| | | indexer.modifyEntry(oldEntry, newEntry, mods, modifiedKeys); |
| | | |
| | | for (Map.Entry<ByteString, Boolean> modifiedKey : modifiedKeys.entrySet()) |
| | | { |
| | |
| | | * |
| | | * |
| | | * Copyright 2006-2008 Sun Microsystems, Inc. |
| | | * Portions copyright 2012-2014 ForgeRock AS. |
| | | * Portions copyright 2012-2015 ForgeRock AS. |
| | | */ |
| | | package org.opends.server.backends.jeb; |
| | | |
| | |
| | | |
| | | import org.forgerock.opendj.ldap.ByteSequence; |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | | import org.forgerock.opendj.ldap.spi.IndexingOptions; |
| | | import org.opends.server.backends.jeb.AttributeIndex.KeyComparator; |
| | | import org.opends.server.types.Entry; |
| | | import org.opends.server.types.Modification; |
| | |
| | | * |
| | | * @param entry The entry. |
| | | * @param keys The set into which the generated keys will be inserted. |
| | | * @param options The indexing options to use |
| | | */ |
| | | public abstract void indexEntry(Entry entry, Set<ByteString> keys, IndexingOptions options); |
| | | public abstract void indexEntry(Entry entry, Set<ByteString> keys); |
| | | |
| | | /** |
| | | * Generate the set of index keys to be added and the set of index keys |
| | |
| | | * @param newEntry The new entry contents. |
| | | * @param mods The set of modifications that were applied to the entry. |
| | | * @param modifiedKeys The map into which the modified keys will be inserted. |
| | | * @param options The indexing options to use |
| | | */ |
| | | public abstract void modifyEntry(Entry oldEntry, Entry newEntry, |
| | | List<Modification> mods, Map<ByteString, Boolean> modifiedKeys, |
| | | IndexingOptions options); |
| | | List<Modification> mods, Map<ByteString, Boolean> modifiedKeys); |
| | | |
| | | /** |
| | | * Get a string representation of this object. The returned value is |
| | |
| | | |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | | import org.forgerock.opendj.ldap.ConditionResult; |
| | | import org.forgerock.opendj.ldap.spi.IndexingOptions; |
| | | import org.opends.server.types.DirectoryException; |
| | | import org.opends.server.types.Entry; |
| | | import org.opends.server.types.Modification; |
| | |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public void addEntry(IndexBuffer buffer, EntryID entryID, Entry entry, IndexingOptions options) |
| | | public void addEntry(IndexBuffer buffer, EntryID entryID, Entry entry) |
| | | throws DatabaseException, DirectoryException |
| | | { |
| | | // Do nothing. |
| | |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public void removeEntry(IndexBuffer buffer, EntryID entryID, Entry entry, IndexingOptions options) |
| | | public void removeEntry(IndexBuffer buffer, EntryID entryID, Entry entry) |
| | | throws DatabaseException, DirectoryException |
| | | { |
| | | // Do nothing. |
| | |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public void modifyEntry(IndexBuffer buffer, EntryID entryID, Entry oldEntry, Entry newEntry, List<Modification> mods, |
| | | IndexingOptions options) throws DatabaseException |
| | | public void modifyEntry(IndexBuffer buffer, EntryID entryID, Entry oldEntry, Entry newEntry, List<Modification> mods) |
| | | throws DatabaseException |
| | | { |
| | | // Do nothing. |
| | | } |
| | |
| | | import java.util.Set; |
| | | |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | | import org.forgerock.opendj.ldap.spi.IndexingOptions; |
| | | import org.opends.server.types.Attribute; |
| | | import org.opends.server.types.AttributeType; |
| | | import org.opends.server.types.Entry; |
| | |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public void indexEntry(Entry entry, Set<ByteString> keys, IndexingOptions options) |
| | | public void indexEntry(Entry entry, Set<ByteString> keys) |
| | | { |
| | | List<Attribute> attrList = entry.getAttribute(attributeType); |
| | | if (attrList != null && !attrList.isEmpty()) |
| | |
| | | @Override |
| | | public void modifyEntry(Entry oldEntry, Entry newEntry, |
| | | List<Modification> mods, |
| | | Map<ByteString, Boolean> modifiedKeys, IndexingOptions options) |
| | | Map<ByteString, Boolean> modifiedKeys) |
| | | { |
| | | List<Attribute> newAttributes = newEntry.getAttribute(attributeType, true); |
| | | List<Attribute> oldAttributes = oldEntry.getAttribute(attributeType, true); |
| | |
| | | entryContainer.getID2Subtree().setTrusted(null, trusted); |
| | | for (AttributeIndex attributeIndex : entryContainer.getAttributeIndexes()) |
| | | { |
| | | setTrusted(attributeIndex.getEqualityIndex(), trusted); |
| | | setTrusted(attributeIndex.getPresenceIndex(), trusted); |
| | | setTrusted(attributeIndex.getSubstringIndex(), trusted); |
| | | setTrusted(attributeIndex.getOrderingIndex(), trusted); |
| | | setTrusted(attributeIndex.getApproximateIndex(), trusted); |
| | | Map<String, Collection<Index>> exIndexes = attributeIndex.getExtensibleIndexes(); |
| | | if(!exIndexes.isEmpty()) |
| | | for (Index index : attributeIndex.getAllIndexes()) |
| | | { |
| | | setTrusted(exIndexes.get(EXTENSIBLE_INDEXER_ID_SUBSTRING), trusted); |
| | | setTrusted(exIndexes.get(EXTENSIBLE_INDEXER_ID_SHARED), trusted); |
| | | setTrusted(index, trusted); |
| | | } |
| | | } |
| | | for(VLVIndex vlvIdx : entryContainer.getVLVIndexes()) { |
| | | for (VLVIndex vlvIdx : entryContainer.getVLVIndexes()) |
| | | { |
| | | vlvIdx.setTrusted(null, trusted); |
| | | } |
| | | } |
| | |
| | | } |
| | | } |
| | | |
| | | private void setTrusted(Collection<Index> subIndexes, boolean trusted) |
| | | { |
| | | if (subIndexes != null) |
| | | { |
| | | for (Index subIndex : subIndexes) |
| | | { |
| | | subIndex.setTrusted(null, trusted); |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Return a src entry container. |
| | | * |
| | |
| | | import org.forgerock.opendj.ldap.DecodeException; |
| | | import org.forgerock.opendj.ldap.ResultCode; |
| | | import org.forgerock.opendj.ldap.schema.MatchingRule; |
| | | import org.forgerock.opendj.ldap.spi.IndexingOptions; |
| | | import org.opends.server.backends.VerifyConfig; |
| | | import org.opends.server.core.DirectoryServer; |
| | | import org.opends.server.types.*; |
| | |
| | | } |
| | | else if (attrIndexList.size() > 0) |
| | | { |
| | | AttributeIndex attrIndex = attrIndexList.get(0); |
| | | final IndexingOptions options = attrIndex.getIndexingOptions(); |
| | | iterateAttrIndex(attrIndex.getEqualityIndex(), options); |
| | | iterateAttrIndex(attrIndex.getPresenceIndex(), options); |
| | | iterateAttrIndex(attrIndex.getSubstringIndex(), options); |
| | | iterateAttrIndex(attrIndex.getOrderingIndex(), options); |
| | | iterateAttrIndex(attrIndex.getApproximateIndex(), options); |
| | | // TODO: Need to iterate through ExtendedMatchingRules indexes. |
| | | for (Index index : attrIndexList.get(0).getAllIndexes()) |
| | | { |
| | | iterateAttrIndex(index); |
| | | } |
| | | } |
| | | else if (vlvIndexList.size() > 0) |
| | | { |
| | |
| | | * @throws JebException If an error occurs in the JE backend. |
| | | * @throws DatabaseException If an error occurs in the JE database. |
| | | */ |
| | | private void iterateAttrIndex(Index index, IndexingOptions options) |
| | | throws JebException, DatabaseException |
| | | private void iterateAttrIndex(Index index) throws JebException, DatabaseException |
| | | { |
| | | if (index == null) |
| | | { |
| | |
| | | |
| | | }; |
| | | |
| | | index.indexEntry(entry, dummySet, options); |
| | | index.indexEntry(entry, dummySet); |
| | | |
| | | if (!foundMatchingKey.get()) |
| | | { |
| | |
| | | { |
| | | try |
| | | { |
| | | List<Attribute> attrList = |
| | | entry.getAttribute(attrIndex.getAttributeType()); |
| | | if (attrList != null) |
| | | { |
| | | verifyAttribute(attrIndex, entryID, attrList); |
| | | } |
| | | verifyAttribute(attrIndex, entryID, entry); |
| | | } |
| | | catch (DirectoryException e) |
| | | { |
| | |
| | | * @param attrList The attribute to be checked. |
| | | * @throws DirectoryException If a Directory Server error occurs. |
| | | */ |
| | | private void verifyAttribute(AttributeIndex attrIndex, EntryID entryID, |
| | | List<Attribute> attrList) |
| | | throws DirectoryException |
| | | private void verifyAttribute(AttributeIndex attrIndex, EntryID entryID, Entry entry) throws DirectoryException |
| | | { |
| | | if (attrList == null || attrList.isEmpty()) |
| | | for (Index index : attrIndex.getAllIndexes()) |
| | | { |
| | | return; |
| | | } |
| | | |
| | | Transaction txn = null; |
| | | Index equalityIndex = attrIndex.getEqualityIndex(); |
| | | Index presenceIndex = attrIndex.getPresenceIndex(); |
| | | Index substringIndex = attrIndex.getSubstringIndex(); |
| | | Index orderingIndex = attrIndex.getOrderingIndex(); |
| | | Index approximateIndex = attrIndex.getApproximateIndex(); |
| | | // TODO: Add support for Extended Matching Rules indexes. |
| | | |
| | | if (presenceIndex != null) |
| | | { |
| | | verifyAttributeInIndex(presenceIndex, txn, JEBUtils.presenceKey, entryID); |
| | | } |
| | | |
| | | final DatabaseEntry key = new DatabaseEntry(); |
| | | for (Attribute attr : attrList) |
| | | { |
| | | final AttributeType attrType = attr.getAttributeType(); |
| | | MatchingRule equalityRule = attrType.getEqualityMatchingRule(); |
| | | for (ByteString value : attr) |
| | | final Set<ByteString> keys = new HashSet<>(); |
| | | index.indexEntry(entry, keys); |
| | | for (ByteString key : keys) |
| | | { |
| | | byte[] normalizedBytes = normalize(equalityRule, value); |
| | | |
| | | if (equalityIndex != null) |
| | | { |
| | | key.setData(normalizedBytes); |
| | | verifyAttributeInIndex(equalityIndex, txn, key, entryID); |
| | | } |
| | | |
| | | if (substringIndex != null) |
| | | { |
| | | for (ByteString keyBytes : attrIndex.substringKeys(normalizedBytes)) |
| | | { |
| | | key.setData(keyBytes.toByteArray()); |
| | | verifyAttributeInIndex(substringIndex, txn, key, entryID); |
| | | } |
| | | } |
| | | |
| | | if (orderingIndex != null) |
| | | { |
| | | key.setData(normalize(attrType.getOrderingMatchingRule(), value)); |
| | | verifyAttributeInIndex(orderingIndex, txn, key, entryID); |
| | | } |
| | | |
| | | if (approximateIndex != null) |
| | | { |
| | | key.setData(normalize(attrType.getApproximateMatchingRule(), value)); |
| | | verifyAttributeInIndex(approximateIndex, txn, key, entryID); |
| | | } |
| | | verifyAttributeInIndex(index, null, key, entryID); |
| | | } |
| | | } |
| | | } |
| | | |
| | | private void verifyAttributeInIndex(Index index, Transaction txn, |
| | | DatabaseEntry key, EntryID entryID) |
| | | private void verifyAttributeInIndex(Index index, Transaction txn, ByteString key, EntryID entryID) |
| | | { |
| | | try |
| | | { |
| | | ConditionResult cr = index.containsID(txn, key, entryID); |
| | | final ConditionResult cr = index.containsID(txn, new DatabaseEntry(key.toByteArray()), entryID); |
| | | if (cr == ConditionResult.FALSE) |
| | | { |
| | | if (logger.isTraceEnabled()) |
| | | { |
| | | logger.trace("Missing ID %d%n%s", |
| | | entryID.longValue(), |
| | | keyDump(index, key.getData())); |
| | | keyDump(index, key.toByteArray())); |
| | | } |
| | | errorCount++; |
| | | } |
| | | else if (cr == ConditionResult.UNDEFINED) |
| | | { |
| | | incrEntryLimitStats(index, key.getData()); |
| | | incrEntryLimitStats(index, key.toByteArray()); |
| | | } |
| | | } |
| | | catch (DatabaseException e) |
| | |
| | | |
| | | logger.trace("Error reading database: %s%n%s", |
| | | e.getMessage(), |
| | | keyDump(index, key.getData())); |
| | | keyDump(index, key.toByteArray())); |
| | | } |
| | | errorCount++; |
| | | } |
| | |
| | | { |
| | | AttributeIndex attrIndex = attrIndexList.get(0); |
| | | totalCount = 0; |
| | | totalCount += getRecordCount(attrIndex.getEqualityIndex()); |
| | | totalCount += getRecordCount(attrIndex.getPresenceIndex()); |
| | | totalCount += getRecordCount(attrIndex.getSubstringIndex()); |
| | | totalCount += getRecordCount(attrIndex.getOrderingIndex()); |
| | | totalCount += getRecordCount(attrIndex.getApproximateIndex()); |
| | | // TODO: Add support for Extended Matching Rules indexes. |
| | | for (Index index : attrIndex.getAllIndexes()) |
| | | { |
| | | totalCount += getRecordCount(index); |
| | | } |
| | | } |
| | | else if (vlvIndexList.size() > 0) |
| | | { |
| | |
| | | /** |
| | | * Override in order to perform any additional initialization after the index has opened. |
| | | */ |
| | | void open0(ReadableTransaction txn) throws StorageRuntimeException |
| | | void open0(WriteableTransaction txn) throws StorageRuntimeException |
| | | { |
| | | // Do nothing by default. |
| | | } |
| | |
| | | /** |
| | | * This class implements an attribute indexer for matching rules in a Backend. |
| | | */ |
| | | final class MatchingRuleIndex extends DefaultIndex |
| | | static final class MatchingRuleIndex extends DefaultIndex |
| | | { |
| | | /** |
| | | * The matching rule's indexer. |
| | | */ |
| | | private final AttributeType attributeType; |
| | | private final Indexer indexer; |
| | | |
| | | private MatchingRuleIndex(WriteableTransaction txn, BackendIndexCfg cfg, Indexer indexer) |
| | | private MatchingRuleIndex(EntryContainer entryContainer, AttributeType attributeType, State state, Indexer indexer, |
| | | int indexEntryLimit) |
| | | { |
| | | super(getIndexName(attributeType, indexer.getIndexID()), state, cfg.getIndexEntryLimit(), txn, entryContainer); |
| | | super(getIndexName(entryContainer, attributeType, indexer.getIndexID()), state, indexEntryLimit, entryContainer); |
| | | this.attributeType = attributeType; |
| | | this.indexer = indexer; |
| | | } |
| | | |
| | | void indexEntry(Entry entry, Set<ByteString> keys, IndexingOptions options) |
| | | void indexEntry(Entry entry, Set<ByteString> keys) |
| | | { |
| | | List<Attribute> attributes = entry.getAttribute(attributeType, true); |
| | | if (attributes != null) |
| | | { |
| | | indexAttribute(attributes, keys, options); |
| | | indexAttribute(attributes, keys); |
| | | } |
| | | } |
| | | |
| | | private void modifyEntry(Entry oldEntry, Entry newEntry, Map<ByteString, Boolean> modifiedKeys, |
| | | IndexingOptions options) |
| | | private void modifyEntry(Entry oldEntry, Entry newEntry, Map<ByteString, Boolean> modifiedKeys) |
| | | { |
| | | List<Attribute> oldAttributes = oldEntry.getAttribute(attributeType, true); |
| | | if (oldAttributes != null) |
| | | { |
| | | final Set<ByteString> keys = new HashSet<ByteString>(); |
| | | indexAttribute(oldAttributes, keys, options); |
| | | indexAttribute(oldAttributes, keys); |
| | | for (ByteString key : keys) |
| | | { |
| | | modifiedKeys.put(key, false); |
| | |
| | | if (newAttributes != null) |
| | | { |
| | | final Set<ByteString> keys = new HashSet<ByteString>(); |
| | | indexAttribute(newAttributes, keys, options); |
| | | indexAttribute(newAttributes, keys); |
| | | for (ByteString key : keys) |
| | | { |
| | | final Boolean needsAdding = modifiedKeys.get(key); |
| | |
| | | } |
| | | } |
| | | |
| | | private void indexAttribute(List<Attribute> attributes, Set<ByteString> keys, IndexingOptions options) |
| | | private void indexAttribute(List<Attribute> attributes, Set<ByteString> keys) |
| | | { |
| | | for (Attribute attr : attributes) |
| | | { |
| | |
| | | { |
| | | try |
| | | { |
| | | indexer.createKeys(Schema.getDefaultSchema(), value, options, keys); |
| | | indexer.createKeys(Schema.getDefaultSchema(), value, keys); |
| | | |
| | | /* |
| | | * Optimization for presence: return immediately after first value since all values |
| | |
| | | private static final Indexer PRESENCE_INDEXER = new Indexer() |
| | | { |
| | | @Override |
| | | public void createKeys(Schema schema, ByteSequence value, IndexingOptions options, Collection<ByteString> keys) |
| | | throws DecodeException |
| | | public void createKeys(Schema schema, ByteSequence value, Collection<ByteString> keys) throws DecodeException |
| | | { |
| | | keys.add(PRESENCE_KEY); |
| | | } |
| | |
| | | private BackendIndexCfg config; |
| | | |
| | | /** The mapping from names to indexes. */ |
| | | private final Map<String, MatchingRuleIndex> nameToIndexes = new HashMap<String, MatchingRuleIndex>(); |
| | | private final IndexingOptions indexingOptions; |
| | | private Map<String, MatchingRuleIndex> indexIdToIndexes; |
| | | private IndexingOptions indexingOptions; |
| | | private final State state; |
| | | |
| | | /** The attribute type for which this instance will generate index keys. */ |
| | | private final AttributeType attributeType; |
| | | |
| | | AttributeIndex(BackendIndexCfg config, State state, EntryContainer entryContainer, WriteableTransaction txn) |
| | | throws ConfigException |
| | | AttributeIndex(BackendIndexCfg config, State state, EntryContainer entryContainer) throws ConfigException |
| | | { |
| | | this.entryContainer = entryContainer; |
| | | this.config = config; |
| | | this.state = state; |
| | | this.attributeType = config.getAttribute(); |
| | | |
| | | buildPresenceIndex(txn); |
| | | buildIndexes(txn, IndexType.EQUALITY); |
| | | buildIndexes(txn, IndexType.SUBSTRING); |
| | | buildIndexes(txn, IndexType.ORDERING); |
| | | buildIndexes(txn, IndexType.APPROXIMATE); |
| | | buildExtensibleIndexes(txn); |
| | | |
| | | indexingOptions = new IndexingOptionsImpl(config.getSubstringLength()); |
| | | this.indexingOptions = new IndexingOptionsImpl(config.getSubstringLength()); |
| | | this.indexIdToIndexes = Collections.unmodifiableMap(buildIndexes(entryContainer, state, config)); |
| | | } |
| | | |
| | | private void buildPresenceIndex(WriteableTransaction txn) |
| | | private static Map<String, MatchingRuleIndex> buildIndexes(EntryContainer entryContainer, State state, |
| | | BackendIndexCfg config) throws ConfigException |
| | | { |
| | | final IndexType indexType = IndexType.PRESENCE; |
| | | if (config.getIndexType().contains(indexType)) |
| | | { |
| | | String indexID = indexType.toString(); |
| | | nameToIndexes.put(indexID, new MatchingRuleIndex(txn, config, PRESENCE_INDEXER)); |
| | | } |
| | | } |
| | | final AttributeType attributeType = config.getAttribute(); |
| | | final int indexEntryLimit = config.getIndexEntryLimit(); |
| | | final IndexingOptions indexingOptions = new IndexingOptionsImpl(config.getSubstringLength()); |
| | | |
| | | private void buildExtensibleIndexes(WriteableTransaction txn) throws ConfigException |
| | | { |
| | | final IndexType indexType = IndexType.EXTENSIBLE; |
| | | if (config.getIndexType().contains(indexType)) |
| | | { |
| | | final AttributeType attrType = config.getAttribute(); |
| | | Set<String> extensibleRules = config.getIndexExtensibleMatchingRule(); |
| | | if (extensibleRules == null || extensibleRules.isEmpty()) |
| | | final Map<String, MatchingRuleIndex> indexes = new HashMap<>(); |
| | | |
| | | for(IndexType indexType : config.getIndexType()) { |
| | | Collection<? extends Indexer> indexers; |
| | | switch (indexType) |
| | | { |
| | | throw new ConfigException(ERR_CONFIG_INDEX_TYPE_NEEDS_MATCHING_RULE.get(attrType, indexType.toString())); |
| | | case PRESENCE: |
| | | indexers = Collections.singleton(PRESENCE_INDEXER); |
| | | break; |
| | | case EXTENSIBLE: |
| | | indexers = |
| | | getExtensibleIndexers(config.getAttribute(), config.getIndexExtensibleMatchingRule(), indexingOptions); |
| | | break; |
| | | case APPROXIMATE: |
| | | indexers = |
| | | throwIfNoMatchingRule(attributeType, indexType, attributeType.getApproximateMatchingRule()).createIndexers( |
| | | indexingOptions); |
| | | break; |
| | | case EQUALITY: |
| | | indexers = |
| | | throwIfNoMatchingRule(attributeType, indexType, attributeType.getEqualityMatchingRule()).createIndexers( |
| | | indexingOptions); |
| | | break; |
| | | case ORDERING: |
| | | indexers = |
| | | throwIfNoMatchingRule(attributeType, indexType, attributeType.getOrderingMatchingRule()).createIndexers( |
| | | indexingOptions); |
| | | break; |
| | | case SUBSTRING: |
| | | indexers = |
| | | throwIfNoMatchingRule(attributeType, indexType, attributeType.getSubstringMatchingRule()).createIndexers( |
| | | indexingOptions); |
| | | break; |
| | | default: |
| | | throw new ConfigException(ERR_CONFIG_INDEX_TYPE_NEEDS_MATCHING_RULE.get(attributeType, indexType.toString())); |
| | | } |
| | | buildIndexesForIndexers(entryContainer, attributeType, state, indexes, indexEntryLimit, indexers); |
| | | } |
| | | return indexes; |
| | | } |
| | | |
| | | // Iterate through the Set and create the index only if necessary. |
| | | // Collation equality and Ordering matching rules share the same indexer and index |
| | | // A Collation substring matching rule is treated differently |
| | | // as it uses a separate indexer and index. |
| | | for (final String ruleName : extensibleRules) |
| | | private static MatchingRule throwIfNoMatchingRule(AttributeType attributeType, IndexType type, MatchingRule rule) |
| | | throws ConfigException |
| | | { |
| | | if (rule == null) |
| | | { |
| | | throw new ConfigException(ERR_CONFIG_INDEX_TYPE_NEEDS_MATCHING_RULE.get(attributeType, type.toString())); |
| | | } |
| | | return rule; |
| | | } |
| | | |
| | | private static void buildIndexesForIndexers(EntryContainer entryContainer, AttributeType attributeType, State state, |
| | | Map<String, MatchingRuleIndex> indexes, int indexEntryLimit, Collection<? extends Indexer> indexers) |
| | | { |
| | | for (Indexer indexer : indexers) |
| | | { |
| | | final String indexID = indexer.getIndexID(); |
| | | if (!indexes.containsKey(indexID)) |
| | | { |
| | | MatchingRule rule = DirectoryServer.getMatchingRule(toLowerCase(ruleName)); |
| | | if (rule == null) |
| | | { |
| | | logger.error(ERR_CONFIG_INDEX_TYPE_NEEDS_VALID_MATCHING_RULE, attrType, ruleName); |
| | | continue; |
| | | } |
| | | for (Indexer indexer : rule.getIndexers()) |
| | | { |
| | | final String indexId = indexer.getIndexID(); |
| | | if (!nameToIndexes.containsKey(indexId)) |
| | | { |
| | | // There is no index available for this index id. Create a new index |
| | | nameToIndexes.put(indexId, new MatchingRuleIndex(txn, config, indexer)); |
| | | } |
| | | } |
| | | indexes.put(indexID, new MatchingRuleIndex(entryContainer, attributeType, state, indexer, indexEntryLimit)); |
| | | } |
| | | } |
| | | } |
| | | |
| | | private void buildIndexes(WriteableTransaction txn, IndexType indexType) throws ConfigException |
| | | private static Collection<Indexer> getExtensibleIndexers(AttributeType attributeType, Set<String> extensibleRules, |
| | | IndexingOptions options) throws ConfigException |
| | | { |
| | | if (config.getIndexType().contains(indexType)) |
| | | if (extensibleRules == null || extensibleRules.isEmpty()) |
| | | { |
| | | final AttributeType attrType = config.getAttribute(); |
| | | final String indexID = indexType.toString(); |
| | | final MatchingRule rule = getMatchingRule(indexType, attrType); |
| | | if (rule == null) |
| | | { |
| | | throw new ConfigException(ERR_CONFIG_INDEX_TYPE_NEEDS_MATCHING_RULE.get(attrType, indexID)); |
| | | } |
| | | |
| | | for (Indexer indexer : rule.getIndexers()) |
| | | { |
| | | nameToIndexes.put(indexer.getIndexID(), new MatchingRuleIndex(txn, config, indexer)); |
| | | } |
| | | throw new ConfigException( |
| | | ERR_CONFIG_INDEX_TYPE_NEEDS_MATCHING_RULE.get(attributeType, IndexType.EXTENSIBLE.toString())); |
| | | } |
| | | |
| | | final Collection<Indexer> indexers = new ArrayList<>(); |
| | | for (final String ruleName : extensibleRules) |
| | | { |
| | | final MatchingRule rule = DirectoryServer.getMatchingRule(toLowerCase(ruleName)); |
| | | throwIfNoMatchingRule(attributeType, IndexType.EXTENSIBLE, rule); |
| | | indexers.addAll(rule.createIndexers(options)); |
| | | } |
| | | |
| | | return indexers; |
| | | } |
| | | |
| | | private MatchingRule getMatchingRule(IndexType indexType, AttributeType attrType) |
| | | private static TreeName getIndexName(EntryContainer entryContainer, AttributeType attrType, String indexID) |
| | | { |
| | | switch (indexType) |
| | | { |
| | | case APPROXIMATE: |
| | | return attrType.getApproximateMatchingRule(); |
| | | case EQUALITY: |
| | | return attrType.getEqualityMatchingRule(); |
| | | case ORDERING: |
| | | return attrType.getOrderingMatchingRule(); |
| | | case SUBSTRING: |
| | | return attrType.getSubstringMatchingRule(); |
| | | default: |
| | | throw new IllegalArgumentException("Not implemented for index type " + indexType); |
| | | } |
| | | } |
| | | |
| | | private TreeName getIndexName(AttributeType attrType, String indexID) |
| | | { |
| | | final String attrIndexId = attrType.getNameOrOID() + "." + indexID; |
| | | return new TreeName(entryContainer.getTreePrefix(), attrIndexId); |
| | | return new TreeName(entryContainer.getTreePrefix(), attrType.getNameOrOID() + "." + indexID); |
| | | } |
| | | |
| | | /** |
| | |
| | | */ |
| | | void open(WriteableTransaction txn) throws StorageRuntimeException |
| | | { |
| | | for (Index index : nameToIndexes.values()) |
| | | for (Index index : indexIdToIndexes.values()) |
| | | { |
| | | index.open(txn); |
| | | } |
| | |
| | | */ |
| | | void addEntry(IndexBuffer buffer, EntryID entryID, Entry entry) throws StorageRuntimeException, DirectoryException |
| | | { |
| | | for (MatchingRuleIndex index : nameToIndexes.values()) |
| | | for (MatchingRuleIndex index : indexIdToIndexes.values()) |
| | | { |
| | | HashSet<ByteString> keys = new HashSet<ByteString>(); |
| | | index.indexEntry(entry, keys, indexingOptions); |
| | | final Set<ByteString> keys = new HashSet<>(); |
| | | index.indexEntry(entry, keys); |
| | | for (ByteString key : keys) |
| | | { |
| | | buffer.put(index, key, entryID); |
| | |
| | | */ |
| | | void removeEntry(IndexBuffer buffer, EntryID entryID, Entry entry) throws StorageRuntimeException, DirectoryException |
| | | { |
| | | for (MatchingRuleIndex index : nameToIndexes.values()) |
| | | for (MatchingRuleIndex index : indexIdToIndexes.values()) |
| | | { |
| | | HashSet<ByteString> keys = new HashSet<ByteString>(); |
| | | index.indexEntry(entry, keys, indexingOptions); |
| | | index.indexEntry(entry, keys); |
| | | for (ByteString key : keys) |
| | | { |
| | | buffer.remove(index, key, entryID); |
| | |
| | | */ |
| | | void modifyEntry(IndexBuffer buffer, EntryID entryID, Entry oldEntry, Entry newEntry) throws StorageRuntimeException |
| | | { |
| | | for (MatchingRuleIndex index : nameToIndexes.values()) |
| | | for (MatchingRuleIndex index : indexIdToIndexes.values()) |
| | | { |
| | | TreeMap<ByteString, Boolean> modifiedKeys = new TreeMap<ByteString, Boolean>(); |
| | | index.modifyEntry(oldEntry, newEntry, modifiedKeys, indexingOptions); |
| | | index.modifyEntry(oldEntry, newEntry, modifiedKeys); |
| | | for (Map.Entry<ByteString, Boolean> modifiedKey : modifiedKeys.entrySet()) |
| | | { |
| | | if (modifiedKey.getValue()) |
| | |
| | | return true; |
| | | } |
| | | |
| | | private boolean isIndexAcceptable(BackendIndexCfg cfg, IndexType indexType, |
| | | private static boolean isIndexAcceptable(BackendIndexCfg cfg, IndexType indexType, |
| | | List<LocalizableMessage> unacceptableReasons) |
| | | { |
| | | final String indexId = indexType.toString(); |
| | | final AttributeType attrType = cfg.getAttribute(); |
| | | if (cfg.getIndexType().contains(indexType) |
| | | && nameToIndexes.get(indexId) == null |
| | | && getMatchingRule(indexType, attrType) == null) |
| | | { |
| | | unacceptableReasons.add(ERR_CONFIG_INDEX_TYPE_NEEDS_MATCHING_RULE.get(attrType, indexId)); |
| | | unacceptableReasons.add(ERR_CONFIG_INDEX_TYPE_NEEDS_MATCHING_RULE.get(attrType, indexType)); |
| | | return false; |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | private static MatchingRule getMatchingRule(IndexType indexType, AttributeType attrType) |
| | | { |
| | | switch (indexType) |
| | | { |
| | | case APPROXIMATE: |
| | | return attrType.getApproximateMatchingRule(); |
| | | case EQUALITY: |
| | | return attrType.getEqualityMatchingRule(); |
| | | case ORDERING: |
| | | return attrType.getOrderingMatchingRule(); |
| | | case SUBSTRING: |
| | | return attrType.getSubstringMatchingRule(); |
| | | default: |
| | | throw new IllegalArgumentException("Not implemented for index type " + indexType); |
| | | } |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public synchronized ConfigChangeResult applyConfigurationChange(final BackendIndexCfg cfg) |
| | | public synchronized ConfigChangeResult applyConfigurationChange(final BackendIndexCfg newConfiguration) |
| | | { |
| | | final ConfigChangeResult ccr = new ConfigChangeResult(); |
| | | final IndexingOptions newIndexingOptions = new IndexingOptionsImpl(newConfiguration.getSubstringLength()); |
| | | try |
| | | { |
| | | final Map<String, MatchingRuleIndex> newIndexIdToIndexes = buildIndexes(entryContainer, state, newConfiguration); |
| | | |
| | | final Map<String, MatchingRuleIndex> removedIndexes = new HashMap<>(indexIdToIndexes); |
| | | removedIndexes.keySet().removeAll(newIndexIdToIndexes.keySet()); |
| | | |
| | | final Map<String, MatchingRuleIndex> addedIndexes = new HashMap<>(newIndexIdToIndexes); |
| | | addedIndexes.keySet().removeAll(indexIdToIndexes.keySet()); |
| | | |
| | | final Map<String, MatchingRuleIndex> updatedIndexes = new HashMap<>(indexIdToIndexes); |
| | | updatedIndexes.keySet().retainAll(newIndexIdToIndexes.keySet()); |
| | | |
| | | // Replace instances of Index created by buildIndexes() with the one already opened and present in the actual |
| | | // indexIdToIndexes |
| | | newIndexIdToIndexes.putAll(updatedIndexes); |
| | | |
| | | // Open added indexes *before* adding them to indexIdToIndexes |
| | | entryContainer.getRootContainer().getStorage().write(new WriteOperation() |
| | | { |
| | | @Override |
| | | public void run(WriteableTransaction txn) throws Exception |
| | | { |
| | | applyChangeToIndex(txn, IndexType.PRESENCE, cfg, ccr); |
| | | applyChangeToIndex(txn, IndexType.EQUALITY, cfg, ccr); |
| | | applyChangeToIndex(txn, IndexType.SUBSTRING, cfg, ccr); |
| | | applyChangeToIndex(txn, IndexType.ORDERING, cfg, ccr); |
| | | applyChangeToIndex(txn, IndexType.APPROXIMATE, cfg, ccr); |
| | | applyChangeToExtensibleIndexes(txn, cfg, ccr); |
| | | for (MatchingRuleIndex addedIndex : addedIndexes.values()) |
| | | { |
| | | openIndex(txn, addedIndex, ccr); |
| | | } |
| | | } |
| | | }); |
| | | |
| | | config = cfg; |
| | | config = newConfiguration; |
| | | indexingOptions = newIndexingOptions; |
| | | indexIdToIndexes = Collections.unmodifiableMap(newIndexIdToIndexes); |
| | | |
| | | // We get exclusive lock to ensure that no query is actually using the indexes that will be deleted. |
| | | entryContainer.lock(); |
| | | try |
| | | { |
| | | entryContainer.getRootContainer().getStorage().write(new WriteOperation() |
| | | { |
| | | @Override |
| | | public void run(WriteableTransaction txn) throws Exception |
| | | { |
| | | for (MatchingRuleIndex removedIndex : removedIndexes.values()) |
| | | { |
| | | deleteIndex(txn, entryContainer, removedIndex); |
| | | } |
| | | } |
| | | }); |
| | | } |
| | | finally |
| | | { |
| | | entryContainer.unlock(); |
| | | } |
| | | |
| | | for (Index updatedIndex : updatedIndexes.values()) |
| | | { |
| | | updateIndex(updatedIndex, newConfiguration.getIndexEntryLimit(), ccr); |
| | | } |
| | | |
| | | } |
| | | catch(Exception e) |
| | | catch (Exception e) |
| | | { |
| | | ccr.setResultCode(DirectoryServer.getServerErrorResultCode()); |
| | | ccr.addMessage(LocalizableMessage.raw(StaticUtils.stackTraceToSingleLineString(e))); |
| | | } |
| | | |
| | | return ccr; |
| | | } |
| | | |
| | | private void applyChangeToExtensibleIndexes(WriteableTransaction txn, BackendIndexCfg cfg, ConfigChangeResult ccr) |
| | | private static void openIndex(WriteableTransaction txn, MatchingRuleIndex index, ConfigChangeResult ccr) |
| | | { |
| | | final AttributeType attrType = cfg.getAttribute(); |
| | | if (!cfg.getIndexType().contains(IndexType.EXTENSIBLE)) |
| | | { |
| | | final Set<MatchingRule> validRules = Collections.emptySet(); |
| | | final Set<String> validIndexIds = Collections.emptySet(); |
| | | removeIndexesForExtensibleMatchingRules(txn, validRules, validIndexIds); |
| | | return; |
| | | } |
| | | |
| | | final Set<String> extensibleRules = cfg.getIndexExtensibleMatchingRule(); |
| | | final Set<MatchingRule> validRules = new HashSet<MatchingRule>(); |
| | | final Set<String> validIndexIds = new HashSet<String>(); |
| | | final int indexEntryLimit = cfg.getIndexEntryLimit(); |
| | | |
| | | for (String ruleName : extensibleRules) |
| | | { |
| | | MatchingRule rule = DirectoryServer.getMatchingRule(toLowerCase(ruleName)); |
| | | if (rule == null) |
| | | { |
| | | logger.error(ERR_CONFIG_INDEX_TYPE_NEEDS_VALID_MATCHING_RULE, attrType, ruleName); |
| | | continue; |
| | | } |
| | | validRules.add(rule); |
| | | for (Indexer indexer : rule.getIndexers()) |
| | | { |
| | | String indexId = indexer.getIndexID(); |
| | | validIndexIds.add(indexId); |
| | | if (!nameToIndexes.containsKey(indexId)) |
| | | { |
| | | nameToIndexes.put(indexId, openNewIndex(txn, cfg, indexer, ccr)); |
| | | } |
| | | else |
| | | { |
| | | Index index = nameToIndexes.get(indexId); |
| | | if (index.setIndexEntryLimit(indexEntryLimit)) |
| | | { |
| | | ccr.setAdminActionRequired(true); |
| | | ccr.addMessage(NOTE_CONFIG_INDEX_ENTRY_LIMIT_REQUIRES_REBUILD.get(index.getName())); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | removeIndexesForExtensibleMatchingRules(txn, validRules, validIndexIds); |
| | | } |
| | | |
| | | /** Remove indexes which do not correspond to valid rules. */ |
| | | private void removeIndexesForExtensibleMatchingRules(WriteableTransaction txn, Set<MatchingRule> validRules, |
| | | Set<String> validIndexIds) |
| | | { |
| | | final Set<MatchingRule> rulesToDelete = getCurrentExtensibleMatchingRules(); |
| | | rulesToDelete.removeAll(validRules); |
| | | if (!rulesToDelete.isEmpty()) |
| | | { |
| | | entryContainer.exclusiveLock.lock(); |
| | | try |
| | | { |
| | | for (MatchingRule rule: rulesToDelete) |
| | | { |
| | | final List<String> indexIdsToRemove = new ArrayList<String>(); |
| | | for (Indexer indexer : rule.getIndexers()) |
| | | { |
| | | final String indexId = indexer.getIndexID(); |
| | | if (!validIndexIds.contains(indexId)) |
| | | { |
| | | indexIdsToRemove.add(indexId); |
| | | } |
| | | } |
| | | // Delete indexes which are not used |
| | | for (String indexId : indexIdsToRemove) |
| | | { |
| | | Index index = nameToIndexes.get(indexId); |
| | | if (index != null) |
| | | { |
| | | entryContainer.deleteTree(txn, index); |
| | | nameToIndexes.remove(index); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | entryContainer.exclusiveLock.unlock(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | private Set<MatchingRule> getCurrentExtensibleMatchingRules() |
| | | { |
| | | final Set<MatchingRule> rules = new HashSet<MatchingRule>(); |
| | | for (String ruleName : config.getIndexExtensibleMatchingRule()) |
| | | { |
| | | final MatchingRule rule = DirectoryServer.getMatchingRule(toLowerCase(ruleName)); |
| | | if (rule != null) |
| | | { |
| | | rules.add(rule); |
| | | } |
| | | } |
| | | return rules; |
| | | } |
| | | |
| | | private void applyChangeToIndex(final WriteableTransaction txn, final IndexType indexType, final BackendIndexCfg cfg, |
| | | final ConfigChangeResult ccr) |
| | | { |
| | | String indexId = indexType.toString(); |
| | | MatchingRuleIndex index = nameToIndexes.get(indexId); |
| | | if (!cfg.getIndexType().contains(indexType)) |
| | | { |
| | | removeIndex(txn, index, indexType); |
| | | return; |
| | | } |
| | | |
| | | if (index == null) |
| | | { |
| | | if (indexType == IndexType.PRESENCE) |
| | | { |
| | | nameToIndexes.put(indexId, openNewIndex(txn, cfg, PRESENCE_INDEXER, ccr)); |
| | | } |
| | | else |
| | | { |
| | | final MatchingRule matchingRule = getMatchingRule(indexType, cfg.getAttribute()); |
| | | for (Indexer indexer : matchingRule.getIndexers()) |
| | | { |
| | | nameToIndexes.put(indexId, openNewIndex(txn, cfg, indexer, ccr)); |
| | | } |
| | | } |
| | | } |
| | | else |
| | | { |
| | | // already exists. Just update index entry limit. |
| | | if (index.setIndexEntryLimit(cfg.getIndexEntryLimit())) |
| | | { |
| | | ccr.setAdminActionRequired(true); |
| | | ccr.addMessage(NOTE_CONFIG_INDEX_ENTRY_LIMIT_REQUIRES_REBUILD.get(index.getName())); |
| | | } |
| | | |
| | | if (indexType == IndexType.SUBSTRING && config.getSubstringLength() != cfg.getSubstringLength()) |
| | | { |
| | | ccr.setAdminActionRequired(true); |
| | | ccr.addMessage(NOTE_CONFIG_INDEX_SUBSTRING_LENGTH_REQUIRES_REBUILD.get(index.getName())); |
| | | } |
| | | } |
| | | } |
| | | |
| | | private void removeIndex(WriteableTransaction txn, Index index, IndexType indexType) |
| | | { |
| | | if (index != null) |
| | | { |
| | | entryContainer.exclusiveLock.lock(); |
| | | try |
| | | { |
| | | nameToIndexes.remove(indexType.toString()); |
| | | entryContainer.deleteTree(txn, index); |
| | | } |
| | | finally |
| | | { |
| | | entryContainer.exclusiveLock.unlock(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | private MatchingRuleIndex openNewIndex(WriteableTransaction txn, BackendIndexCfg cfg, Indexer indexer, |
| | | ConfigChangeResult ccr) |
| | | { |
| | | final MatchingRuleIndex index = new MatchingRuleIndex(txn, cfg, indexer); |
| | | index.open(txn); |
| | | |
| | | if (!index.isTrusted()) |
| | | { |
| | | ccr.setAdminActionRequired(true); |
| | | ccr.addMessage(NOTE_INDEX_ADD_REQUIRES_REBUILD.get(index.getName())); |
| | | } |
| | | return index; |
| | | } |
| | | |
| | | private static void updateIndex(Index updatedIndex, int newIndexEntryLimit, ConfigChangeResult ccr) |
| | | { |
| | | if (updatedIndex.setIndexEntryLimit(newIndexEntryLimit)) |
| | | { |
| | | // This index can still be used since index size limit doesn't impact validity of the results. |
| | | ccr.setAdminActionRequired(true); |
| | | ccr.addMessage(NOTE_CONFIG_INDEX_ENTRY_LIMIT_REQUIRES_REBUILD.get(updatedIndex.getName())); |
| | | } |
| | | } |
| | | |
| | | private static void deleteIndex(WriteableTransaction txn, EntryContainer entryContainer, Index index) |
| | | { |
| | | entryContainer.exclusiveLock.lock(); |
| | | try |
| | | { |
| | | entryContainer.deleteTree(txn, index); |
| | | } |
| | | finally |
| | | { |
| | | entryContainer.exclusiveLock.unlock(); |
| | | } |
| | | } |
| | | |
| | | /** |
| | |
| | | */ |
| | | boolean isTrusted() |
| | | { |
| | | for (Index index : nameToIndexes.values()) |
| | | for (Index index : indexIdToIndexes.values()) |
| | | { |
| | | if (!index.isTrusted()) |
| | | { |
| | |
| | | |
| | | Map<String, MatchingRuleIndex> getNameToIndexes() |
| | | { |
| | | return Collections.unmodifiableMap(nameToIndexes); |
| | | return indexIdToIndexes; |
| | | } |
| | | |
| | | /** |
| | |
| | | if (debugBuffer != null) |
| | | { |
| | | debugBuffer.append("[INDEX:"); |
| | | for (Indexer indexer : rule.getIndexers()) |
| | | for (Indexer indexer : rule.createIndexers(indexingOptions)) |
| | | { |
| | | debugBuffer.append(" ") |
| | | .append(filter.getAttributeType().getNameOrOID()) |
| | |
| | | |
| | | private boolean ruleHasAtLeastOneIndex(MatchingRule rule) |
| | | { |
| | | for (Indexer indexer : rule.getIndexers()) |
| | | for (Indexer indexer : rule.createIndexers(indexingOptions)) |
| | | { |
| | | if (nameToIndexes.containsKey(indexer.getIndexID())) |
| | | if (indexIdToIndexes.containsKey(indexer.getIndexID())) |
| | | { |
| | | return true; |
| | | } |
| | |
| | | } |
| | | |
| | | /** Indexing options implementation. */ |
| | | private final class IndexingOptionsImpl implements IndexingOptions |
| | | private static final class IndexingOptionsImpl implements IndexingOptions |
| | | { |
| | | /** The length of substring keys used in substring indexes. */ |
| | | private int substringKeySize; |
| | |
| | | void closeAndDelete(WriteableTransaction txn) |
| | | { |
| | | close(); |
| | | for (Index index : nameToIndexes.values()) |
| | | for (Index index : indexIdToIndexes.values()) |
| | | { |
| | | index.delete(txn); |
| | | state.deleteRecord(txn, index.getName()); |
| | |
| | | |
| | | private final State state; |
| | | |
| | | private final EntryIDSetCodec codec; |
| | | private final EntryContainer entryContainer; |
| | | |
| | | private EntryIDSetCodec codec; |
| | | |
| | | /** |
| | | * A flag to indicate if this index should be trusted to be consistent with the entries tree. |
| | |
| | | * The state tree to persist index state info. |
| | | * @param indexEntryLimit |
| | | * The configured limit on the number of entry IDs that may be indexed by one key. |
| | | * @param txn |
| | | * a non null transaction |
| | | * @param entryContainer |
| | | * The entryContainer holding this index. |
| | | * @throws StorageRuntimeException |
| | | * If an error occurs in the storage. |
| | | */ |
| | | DefaultIndex(TreeName name, State state, int indexEntryLimit, WriteableTransaction txn, EntryContainer entryContainer) |
| | | DefaultIndex(TreeName name, State state, int indexEntryLimit, EntryContainer entryContainer) |
| | | throws StorageRuntimeException |
| | | { |
| | | super(name); |
| | | this.indexEntryLimit = indexEntryLimit; |
| | | this.state = state; |
| | | this.entryContainer = entryContainer; |
| | | } |
| | | |
| | | @Override |
| | | final void open0(WriteableTransaction txn) |
| | | { |
| | | final EnumSet<IndexFlag> flags = state.getIndexFlags(txn, getName()); |
| | | this.codec = flags.contains(COMPACTED) ? CODEC_V2 : CODEC_V1; |
| | | this.trusted = flags.contains(TRUSTED); |
| | | codec = flags.contains(COMPACTED) ? CODEC_V2 : CODEC_V1; |
| | | trusted = flags.contains(TRUSTED); |
| | | if (!trusted && entryContainer.getHighestEntryID(txn).longValue() == 0) |
| | | { |
| | | // If there are no entries in the entry container then there |
| | |
| | | { |
| | | try |
| | | { |
| | | // FIXME this should be a read operation, but I cannot change it |
| | | // because of AttributeIndex ctor. |
| | | storage.write(new WriteOperation() |
| | | { |
| | | @Override |
| | | public void run(WriteableTransaction txn) throws Exception |
| | | { |
| | | //Try creating all the indexes before confirming they are valid ones. |
| | | new AttributeIndex(cfg, state, EntryContainer.this, txn); |
| | | } |
| | | }); |
| | | new AttributeIndex(cfg, state, EntryContainer.this); |
| | | return true; |
| | | } |
| | | catch(Exception e) |
| | |
| | | final ConfigChangeResult ccr = new ConfigChangeResult(); |
| | | try |
| | | { |
| | | final AttributeIndex index = new AttributeIndex(cfg, state, EntryContainer.this); |
| | | storage.write(new WriteOperation() |
| | | { |
| | | @Override |
| | | public void run(WriteableTransaction txn) throws Exception |
| | | { |
| | | final AttributeIndex index = new AttributeIndex(cfg, state, EntryContainer.this, txn); |
| | | index.open(txn); |
| | | if (!index.isTrusted()) |
| | | { |
| | |
| | | { |
| | | BackendIndexCfg indexCfg = config.getBackendIndex(idx); |
| | | |
| | | AttributeIndex index = new AttributeIndex(indexCfg, state, this, txn); |
| | | final AttributeIndex index = new AttributeIndex(indexCfg, state, this); |
| | | index.open(txn); |
| | | if(!index.isTrusted()) |
| | | { |
| | |
| | | } |
| | | |
| | | // Move this entry. |
| | | removeSubordinateEntry(txn, buffer, oldSuperiorDN, oldID, newID, oldEntry, newDN, isApexEntryMoved, |
| | | modifyDNOperation, current); |
| | | removeSubordinateEntry(txn, buffer, oldID, newID, oldEntry, newDN, modifyDNOperation, current); |
| | | current = current.next; |
| | | |
| | | if (modifyDNOperation != null) |
| | |
| | | } |
| | | |
| | | private void removeSubordinateEntry(WriteableTransaction txn, IndexBuffer buffer, |
| | | DN oldSuperiorDN, |
| | | EntryID oldID, EntryID newID, |
| | | Entry oldEntry, DN newDN, |
| | | boolean isApexEntryMoved, |
| | | ModifyDNOperation modifyDNOperation, |
| | | MovedEntry tail) |
| | | throws DirectoryException, StorageRuntimeException |
| | |
| | | import org.forgerock.opendj.ldap.ByteSequenceReader; |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | | import org.forgerock.opendj.ldap.ByteStringBuilder; |
| | | import org.forgerock.opendj.ldap.spi.IndexingOptions; |
| | | import org.forgerock.util.Utils; |
| | | import org.opends.server.admin.std.meta.BackendIndexCfgDefn.IndexType; |
| | | import org.opends.server.admin.std.server.BackendIndexCfg; |
| | |
| | | } |
| | | |
| | | @Override |
| | | void processAttribute(MatchingRuleIndex index, Entry entry, EntryID entryID, IndexingOptions options, |
| | | IndexKey indexKey) throws StorageRuntimeException, InterruptedException |
| | | void processAttribute(MatchingRuleIndex index, Entry entry, EntryID entryID, IndexKey indexKey) |
| | | throws StorageRuntimeException, InterruptedException |
| | | { |
| | | if (oldEntry != null) |
| | | { |
| | | deleteKeySet.clear(); |
| | | index.indexEntry(oldEntry, deleteKeySet, options); |
| | | index.indexEntry(oldEntry, deleteKeySet); |
| | | for (ByteString delKey : deleteKeySet) |
| | | { |
| | | processKey(index, delKey, entryID, indexKey, false); |
| | | } |
| | | } |
| | | insertKeySet.clear(); |
| | | index.indexEntry(entry, insertKeySet, options); |
| | | index.indexEntry(entry, insertKeySet); |
| | | for (ByteString key : insertKeySet) |
| | | { |
| | | processKey(index, key, entryID, indexKey, true); |
| | |
| | | void fillIndexKey(AttributeIndex attrIndex, Entry entry, AttributeType attrType, EntryID entryID) |
| | | throws InterruptedException, StorageRuntimeException |
| | | { |
| | | final IndexingOptions options = attrIndex.getIndexingOptions(); |
| | | |
| | | for (Map.Entry<String, MatchingRuleIndex> mapEntry : attrIndex.getNameToIndexes().entrySet()) |
| | | { |
| | | processAttribute(mapEntry.getValue(), mapEntry.getKey(), entry, attrType, entryID, options); |
| | | processAttribute(mapEntry.getValue(), mapEntry.getKey(), entry, attrType, entryID); |
| | | } |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | private void processAttribute(MatchingRuleIndex index, String indexID, Entry entry, |
| | | AttributeType attributeType, EntryID entryID, IndexingOptions options) throws InterruptedException |
| | | AttributeType attributeType, EntryID entryID) throws InterruptedException |
| | | { |
| | | if (index != null) |
| | | { |
| | | IndexKey indexKey = new IndexKey(attributeType, indexID, index.getIndexEntryLimit()); |
| | | processAttribute(index, entry, entryID, options, indexKey); |
| | | processAttribute(index, entry, entryID, indexKey); |
| | | } |
| | | } |
| | | |
| | | void processAttribute(MatchingRuleIndex index, Entry entry, EntryID entryID, IndexingOptions options, |
| | | IndexKey indexKey) throws StorageRuntimeException, InterruptedException |
| | | void processAttribute(MatchingRuleIndex index, Entry entry, EntryID entryID, IndexKey indexKey) |
| | | throws StorageRuntimeException, InterruptedException |
| | | { |
| | | insertKeySet.clear(); |
| | | index.indexEntry(entry, insertKeySet, options); |
| | | index.indexEntry(entry, insertKeySet); |
| | | for (ByteString key : insertKeySet) |
| | | { |
| | | processKey(index, key, entryID, indexKey, true); |
| | |
| | | AttributeType attrType = indexKey.getAttributeType(); |
| | | if (entry.hasAttribute(attrType)) |
| | | { |
| | | AttributeIndex attributeIndex = entryContainer.getAttributeIndex(attrType); |
| | | IndexingOptions options = attributeIndex.getIndexingOptions(); |
| | | MatchingRuleIndex index = mapEntry.getValue(); |
| | | processAttribute(index, entry, entryID, options, indexKey); |
| | | processAttribute(mapEntry.getValue(), entry, entryID, indexKey); |
| | | } |
| | | } |
| | | } |
| | |
| | | } |
| | | |
| | | @Override |
| | | void open0(final ReadableTransaction txn) throws StorageRuntimeException |
| | | void open0(final WriteableTransaction txn) throws StorageRuntimeException |
| | | { |
| | | count.set((int) txn.getRecordCount(getName())); |
| | | } |
| | |
| | | import org.forgerock.opendj.ldap.ByteSequence; |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | | import org.forgerock.opendj.ldap.ConditionResult; |
| | | import org.forgerock.opendj.ldap.spi.IndexingOptions; |
| | | import org.opends.server.backends.VerifyConfig; |
| | | import org.opends.server.backends.pluggable.AttributeIndex.MatchingRuleIndex; |
| | | import org.opends.server.backends.pluggable.spi.Cursor; |
| | |
| | | else if (attrIndexList.size() > 0) |
| | | { |
| | | AttributeIndex attrIndex = attrIndexList.get(0); |
| | | final IndexingOptions options = attrIndex.getIndexingOptions(); |
| | | for (MatchingRuleIndex index : attrIndex.getNameToIndexes().values()) |
| | | { |
| | | iterateAttrIndex(txn, index, options); |
| | | iterateAttrIndex(txn, index); |
| | | } |
| | | } |
| | | else if (vlvIndexList.size() > 0) |
| | |
| | | * @param index The index tree to be checked. |
| | | * @throws StorageRuntimeException If an error occurs in the storage. |
| | | */ |
| | | private void iterateAttrIndex(ReadableTransaction txn, MatchingRuleIndex index, IndexingOptions options) |
| | | throws StorageRuntimeException |
| | | private void iterateAttrIndex(ReadableTransaction txn, MatchingRuleIndex index) throws StorageRuntimeException |
| | | { |
| | | if (index == null) |
| | | { |
| | |
| | | |
| | | }; |
| | | |
| | | index.indexEntry(entry, dummySet, options); |
| | | index.indexEntry(entry, dummySet); |
| | | |
| | | if (!foundMatchingKey.get()) |
| | | { |
| | |
| | | */ |
| | | private void verifyAttribute(ReadableTransaction txn, EntryID entryID, Entry entry, AttributeIndex attrIndex) |
| | | { |
| | | IndexingOptions options = attrIndex.getIndexingOptions(); |
| | | for (MatchingRuleIndex index : attrIndex.getNameToIndexes().values()) |
| | | { |
| | | Set<ByteString> keys = new HashSet<ByteString>(); |
| | | index.indexEntry(entry, keys, options); |
| | | index.indexEntry(entry, keys); |
| | | for (ByteString key : keys) |
| | | { |
| | | verifyAttributeInIndex(index, txn, key, entryID); |
| | |
| | | */ |
| | | public final class HistoricalCsnOrderingMatchingRuleImpl implements MatchingRuleImpl |
| | | { |
| | | private static final String ORDERING_ID = "ordering"; |
| | | private static final String ORDERING_ID = "changeSequenceNumberOrderingMatch"; |
| | | |
| | | private final Collection<? extends Indexer> indexers = Collections.singleton(new HistoricalIndexer()); |
| | | |
| | |
| | | private final class HistoricalIndexer implements Indexer |
| | | { |
| | | @Override |
| | | public void createKeys(Schema schema, ByteSequence value, IndexingOptions options, Collection<ByteString> keys) |
| | | throws DecodeException |
| | | public void createKeys(Schema schema, ByteSequence value, Collection<ByteString> keys) throws DecodeException |
| | | { |
| | | keys.add(normalizeAttributeValue(schema, value)); |
| | | } |
| | |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public Collection<? extends Indexer> getIndexers() |
| | | public Collection<? extends Indexer> createIndexers(IndexingOptions options) |
| | | { |
| | | return indexers; |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public boolean isIndexingSupported() |
| | | { |
| | | return !indexers.isEmpty(); |
| | | } |
| | | |
| | | } |
| | |
| | | import org.forgerock.opendj.ldap.spi.IndexingOptions; |
| | | |
| | | import static org.forgerock.opendj.ldap.Assertion.*; |
| | | import static org.opends.server.schema.SchemaConstants.*; |
| | | |
| | | /** |
| | | * Abstract implementation for password matching rules. |
| | |
| | | abstract class AbstractPasswordEqualityMatchingRuleImpl implements MatchingRuleImpl |
| | | { |
| | | |
| | | private static final String EQUALITY_ID = "equality"; |
| | | private static final String EQUALITY_ID = EMR_AUTH_PASSWORD_NAME; |
| | | |
| | | private final Collection<? extends Indexer> indexers = Collections.singleton(new Indexer() |
| | | { |
| | | @Override |
| | | public void createKeys(Schema schema, ByteSequence value, IndexingOptions options, Collection<ByteString> keys) |
| | | throws DecodeException |
| | | public void createKeys(Schema schema, ByteSequence value, Collection<ByteString> keys) throws DecodeException |
| | | { |
| | | keys.add(normalizeAttributeValue(schema, value)); |
| | | } |
| | |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public Collection<? extends Indexer> getIndexers() |
| | | public Collection<? extends Indexer> createIndexers(IndexingOptions options) |
| | | { |
| | | return indexers; |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public boolean isIndexingSupported() |
| | | { |
| | | return !indexers.isEmpty(); |
| | | } |
| | | |
| | | /** |
| | | * Indicates whether the provided attribute value should be considered a match |
| | | * for the given assertion value. This will only be used for the purpose of |
| | |
| | | import org.forgerock.opendj.ldap.schema.MatchingRuleImpl; |
| | | import org.forgerock.opendj.ldap.schema.Schema; |
| | | import org.forgerock.opendj.ldap.spi.Indexer; |
| | | import org.forgerock.opendj.ldap.spi.IndexingOptions; |
| | | |
| | | |
| | | /** |
| | |
| | | } |
| | | |
| | | @Override |
| | | public Collection<? extends Indexer> getIndexers() |
| | | public Collection<? extends Indexer> createIndexers(IndexingOptions options) |
| | | { |
| | | return caseIgnoreMatchingRule.getIndexers(); |
| | | return caseIgnoreMatchingRule.createIndexers(options); |
| | | } |
| | | |
| | | @Override |
| | | public boolean isIndexingSupported() |
| | | { |
| | | return !getIndexers().isEmpty(); |
| | | } |
| | | } |
| | | |
| | |
| | | */ |
| | | package org.opends.server.backends.jeb; |
| | | |
| | | import static org.opends.server.schema.SchemaConstants.*; |
| | | |
| | | import java.io.File; |
| | | import java.io.FileOutputStream; |
| | | import java.io.OutputStream; |
| | | import java.nio.file.Path; |
| | | import java.util.ArrayList; |
| | | import java.util.Collection; |
| | | import java.util.Collections; |
| | | import java.util.HashSet; |
| | | import java.util.LinkedHashSet; |
| | |
| | | */ |
| | | @SuppressWarnings("javadoc") |
| | | public class TestBackendImpl extends JebTestCase { |
| | | |
| | | private String homeDirName; |
| | | |
| | | private BackendImpl backend; |
| | | |
| | | private AttributeType givenName; |
| | | private AttributeType title; |
| | | private AttributeType name; |
| | | |
| | | private List<Entry> topEntries; |
| | | private List<Entry> entries; |
| | | private List<Entry> additionalEntries; |
| | |
| | | "ou: People" |
| | | ); |
| | | |
| | | givenName = DirectoryServer.getAttributeType("givenname"); |
| | | title = DirectoryServer.getAttributeType("title"); |
| | | name = DirectoryServer.getAttributeType("name"); |
| | | } |
| | | |
| | | @AfterClass |
| | |
| | | AttributeIndex index = ec.getAttributeIndex(attribute); |
| | | AttributeType attrType = index.getAttributeType(); |
| | | |
| | | List<? extends Indexer> indexers; |
| | | indexers = singletonList(new PresenceIndexer(index.getAttributeType())); |
| | | assertIndexContainsID(indexers, entry, index.getPresenceIndex(), entryID, FALSE); |
| | | List<? extends Indexer> indexers = singletonList(new PresenceIndexer(index.getAttributeType())); |
| | | assertIndexContainsID(indexers, entry, index.getIndex("presence"), entryID, FALSE); |
| | | |
| | | indexers = newAttributeIndexers(attrType, attrType.getEqualityMatchingRule()); |
| | | assertIndexContainsID(indexers, entry, index.getEqualityIndex(), entryID, FALSE); |
| | | assertIndexContainsID(indexers, entry, index.getIndex(EMR_CASE_IGNORE_NAME), entryID, FALSE); |
| | | |
| | | indexers = newAttributeIndexers(attrType, attrType.getSubstringMatchingRule()); |
| | | assertIndexContainsID(indexers, entry, index.getSubstringIndex(), entryID, FALSE); |
| | | assertIndexContainsID(indexers, entry, index.getIndex(substringIndexId()), entryID, FALSE); |
| | | |
| | | indexers = newAttributeIndexers(attrType, attrType.getOrderingMatchingRule()); |
| | | assertIndexContainsID(indexers, entry, index.getOrderingIndex(), entryID, FALSE); |
| | | // OrderingIndex is now handled by EqualityIndex (OPENDJ-1864) |
| | | assertThat(index.getIndex(OMR_CASE_IGNORE_NAME)).isNull(); |
| | | } |
| | | finally |
| | | { |
| | |
| | | private static List<AttributeIndexer> newAttributeIndexers(AttributeType attrType, MatchingRule matchingRule) |
| | | { |
| | | List<AttributeIndexer> indexers = new ArrayList<AttributeIndexer>(); |
| | | for (org.forgerock.opendj.ldap.spi.Indexer indexer : matchingRule.getIndexers()) |
| | | for (org.forgerock.opendj.ldap.spi.Indexer indexer : matchingRule.createIndexers(getOptions())) |
| | | { |
| | | indexers.add(new AttributeIndexer(attrType, indexer)); |
| | | } |
| | |
| | | for (Indexer indexer : indexers) |
| | | { |
| | | Set<ByteString> addKeys = new HashSet<ByteString>(); |
| | | indexer.indexEntry(entry, addKeys, getOptions()); |
| | | indexer.indexEntry(entry, addKeys); |
| | | |
| | | DatabaseEntry key = new DatabaseEntry(); |
| | | for (ByteString keyBytes : addKeys) |
| | |
| | | for (Indexer indexer : indexers) |
| | | { |
| | | Set<ByteString> addKeys = new HashSet<ByteString>(); |
| | | indexer.indexEntry(entry, addKeys, getOptions()); |
| | | indexer.indexEntry(entry, addKeys); |
| | | |
| | | assertIndexContainsID(addKeys, index, entryID, expected); |
| | | } |
| | |
| | | |
| | | List<? extends Indexer> indexers; |
| | | indexers = newAttributeIndexers(attrType, attrType.getOrderingMatchingRule()); |
| | | assertIndexContainsID(indexers, entry, index.getOrderingIndex(), entryID, TRUE); |
| | | assertIndexContainsID(indexers, oldEntry, index.getOrderingIndex(), entryID, FALSE); |
| | | // OrderingIndex is now handled by EqualityIndex (OPENDJ-1864) |
| | | assertThat(index.getIndex(OMR_CASE_IGNORE_NAME)).isNull(); |
| | | |
| | | indexers = newAttributeIndexers(attrType, attrType.getSubstringMatchingRule()); |
| | | assertIndexContainsID(indexers, entry, index.getSubstringIndex(), entryID, TRUE); |
| | | assertIndexContainsID(indexers, oldEntry, index.getSubstringIndex(), entryID, FALSE); |
| | | assertIndexContainsID(indexers, entry, index.getIndex(substringIndexId()), entryID, TRUE); |
| | | assertIndexContainsID(indexers, oldEntry, index.getIndex(substringIndexId()), entryID, FALSE); |
| | | |
| | | indexers = newAttributeIndexers(attrType, attrType.getEqualityMatchingRule()); |
| | | assertIndexContainsID(indexers, entry, index.getEqualityIndex(), entryID, TRUE); |
| | | assertIndexContainsID(indexers, oldEntry, index.getEqualityIndex(), entryID, FALSE); |
| | | assertIndexContainsID(indexers, entry, index.getIndex(EMR_CASE_IGNORE_NAME), entryID, TRUE); |
| | | assertIndexContainsID(indexers, oldEntry, index.getIndex(EMR_CASE_IGNORE_NAME), entryID, FALSE); |
| | | } |
| | | finally |
| | | { |
| | |
| | | |
| | | assertNotNull(entryID); |
| | | |
| | | attribute = DirectoryServer.getAttributeType("title"); |
| | | titleIndex = ec.getAttributeIndex(attribute); |
| | | attribute = DirectoryServer.getAttributeType("name"); |
| | | nameIndex = ec.getAttributeIndex(attribute); |
| | | titleIndex = ec.getAttributeIndex(title); |
| | | nameIndex = ec.getAttributeIndex(name); |
| | | |
| | | // This current entry in the DB shouldn't be in the presence titleIndex. |
| | | addKeys = new HashSet<ByteString>(); |
| | | addKeys.add(PresenceIndexer.presenceKey); |
| | | assertIndexContainsID(addKeys, titleIndex.getPresenceIndex(), entryID, FALSE); |
| | | assertIndexContainsID(addKeys, titleIndex.getIndex("presence"), entryID, FALSE); |
| | | |
| | | // This current entry should be in the presence nameIndex. |
| | | addKeys = new HashSet<ByteString>(); |
| | | addKeys.add(PresenceIndexer.presenceKey); |
| | | assertIndexContainsID(addKeys, nameIndex.getPresenceIndex(), entryID, TRUE); |
| | | assertIndexContainsID(addKeys, nameIndex.getIndex("presence"), entryID, TRUE); |
| | | |
| | | List<Control> noControls = new ArrayList<Control>(0); |
| | | ModifyOperationBasis modifyOp = new ModifyOperationBasis(getRootConnection(), nextOperationID(), nextMessageID(), |
| | |
| | | AttributeType nameIndexAttrType = nameIndex.getAttributeType(); |
| | | |
| | | indexers = singletonList(new PresenceIndexer(titleIndexAttrType)); |
| | | assertIndexContainsID(indexers, entry, titleIndex.getPresenceIndex(), entryID); |
| | | assertIndexContainsID(indexers, entry, titleIndex.getIndex("presence"), entryID); |
| | | indexers = singletonList(new PresenceIndexer(nameIndexAttrType)); |
| | | assertIndexContainsID(indexers, entry, nameIndex.getPresenceIndex(), entryID); |
| | | assertIndexContainsID(indexers, entry, nameIndex.getIndex("presence"), entryID); |
| | | |
| | | indexers = newAttributeIndexers(titleIndexAttrType, titleIndexAttrType.getOrderingMatchingRule()); |
| | | assertIndexContainsID(indexers, entry, titleIndex.getOrderingIndex(), entryID); |
| | | indexers = newAttributeIndexers(nameIndexAttrType, nameIndexAttrType.getOrderingMatchingRule()); |
| | | assertIndexContainsID(indexers, entry, nameIndex.getOrderingIndex(), entryID); |
| | | // OrderingIndex is now handled by EqualityIndex (OPENDJ-1864) |
| | | assertThat(getIndexNames(titleIndex)).containsOnly( |
| | | indexName(ec, titleIndexAttrType, "presence"), |
| | | indexName(ec, titleIndexAttrType, EMR_CASE_IGNORE_NAME), |
| | | indexName(ec, titleIndexAttrType, SMR_CASE_IGNORE_NAME + ":6")); |
| | | assertThat(getIndexNames(nameIndex)).containsOnly( |
| | | indexName(ec, nameIndexAttrType, "presence"), |
| | | indexName(ec, nameIndexAttrType, AMR_DOUBLE_METAPHONE_NAME), |
| | | indexName(ec, nameIndexAttrType, EMR_CASE_IGNORE_NAME), |
| | | indexName(ec, nameIndexAttrType, SMR_CASE_IGNORE_NAME + ":6")); |
| | | |
| | | indexers = newAttributeIndexers(titleIndexAttrType, titleIndexAttrType.getEqualityMatchingRule()); |
| | | assertIndexContainsID(indexers, entry, titleIndex.getEqualityIndex(), entryID); |
| | | assertIndexContainsID(indexers, entry, titleIndex.getIndex(EMR_CASE_IGNORE_NAME), entryID); |
| | | indexers = newAttributeIndexers(nameIndexAttrType, nameIndexAttrType.getEqualityMatchingRule()); |
| | | assertIndexContainsID(indexers, entry, nameIndex.getEqualityIndex(), entryID); |
| | | assertIndexContainsID(indexers, entry, nameIndex.getIndex(EMR_CASE_IGNORE_NAME), entryID); |
| | | |
| | | indexers = newAttributeIndexers(titleIndexAttrType, titleIndexAttrType.getSubstringMatchingRule()); |
| | | assertIndexContainsID(indexers, entry, titleIndex.getSubstringIndex(), entryID); |
| | | assertIndexContainsID(indexers, entry, titleIndex.getIndex(substringIndexId()), entryID); |
| | | indexers = newAttributeIndexers(nameIndexAttrType, nameIndexAttrType.getSubstringMatchingRule()); |
| | | assertIndexContainsID(indexers, entry, nameIndex.getSubstringIndex(), entryID); |
| | | assertIndexContainsID(indexers, entry, nameIndex.getIndex(substringIndexId()), entryID); |
| | | } |
| | | finally |
| | | { |
| | |
| | | assertNotNull(rootContainer.getEntryContainer(DN.valueOf("dc=newsuffix,dc=com"))); |
| | | } |
| | | |
| | | /** @since OPENDJ-1864 Equality and Ordering indexes share the same database */ |
| | | @Test |
| | | public void testRemovingOrderingIndexDoesNotRemoveEquality() throws Exception |
| | | { |
| | | int resultCode = TestCaseUtils.applyModifications(true, |
| | | "dn: ds-cfg-attribute=givenName,cn=Index,ds-cfg-backend-id=indexRoot,cn=Backends,cn=config", |
| | | "changetype: modify", |
| | | "replace: ds-cfg-index-type", |
| | | "ds-cfg-index-type: equality", |
| | | "ds-cfg-index-type: ordering"); |
| | | assertEquals(resultCode, 0); |
| | | |
| | | RootContainer rootContainer = backend.getRootContainer(); |
| | | EntryContainer ec = rootContainer.getEntryContainer(DN.valueOf("dc=test,dc=com")); |
| | | |
| | | Collection<String> containerNames = getContainerNames(ec); |
| | | assertThat(containerNames).contains(indexName(ec, givenName, EMR_CASE_IGNORE_NAME)); |
| | | assertThat(containerNames).doesNotContain(indexName(ec, givenName, OMR_CASE_IGNORE_NAME)); |
| | | |
| | | // Remove equality indexes |
| | | resultCode = TestCaseUtils.applyModifications(true, |
| | | "dn: ds-cfg-attribute=givenName,cn=Index,ds-cfg-backend-id=indexRoot,cn=Backends,cn=config", |
| | | "changetype: modify", |
| | | "replace: ds-cfg-index-type", |
| | | "ds-cfg-index-type: ordering"); |
| | | assertEquals(resultCode, 0); |
| | | |
| | | // Since ordering is using the same equality db, it must remain |
| | | containerNames = getContainerNames(ec); |
| | | assertThat(containerNames).contains(indexName(ec, givenName, EMR_CASE_IGNORE_NAME)); |
| | | assertThat(containerNames).doesNotContain(indexName(ec, givenName, OMR_CASE_IGNORE_NAME)); |
| | | } |
| | | |
| | | @Test(dependsOnMethods = {"testModifyDN", |
| | | "testSearchScope", "testSearchIndex", "testReplaceEntry", |
| | | "testModifyEntry", "testModifyDN", "testDeleteSubtree", |
| | |
| | | "testModifyDNNewSuperior", "testMatchedDN"}) |
| | | public void testApplyIndexConfig() throws Exception { |
| | | int resultCode = TestCaseUtils.applyModifications(true, |
| | | "dn: ds-cfg-attribute=givenName,cn=Index," + |
| | | "ds-cfg-backend-id=indexRoot,cn=Backends,cn=config", |
| | | "dn: ds-cfg-attribute=givenName,cn=Index,ds-cfg-backend-id=indexRoot,cn=Backends,cn=config", |
| | | "changetype: modify", |
| | | "replace: ds-cfg-index-type", |
| | | "ds-cfg-index-type: approximate"); |
| | |
| | | RootContainer rootContainer = backend.getRootContainer(); |
| | | EntryContainer ec = rootContainer.getEntryContainer(DN.valueOf("dc=test,dc=com")); |
| | | |
| | | AttributeType givennameAttr = DirectoryServer.getAttributeType("givenname"); |
| | | AttributeIndex attributeIndex = ec.getAttributeIndex(givennameAttr); |
| | | assertNull(attributeIndex.getEqualityIndex()); |
| | | assertNull(attributeIndex.getPresenceIndex()); |
| | | assertNull(attributeIndex.getSubstringIndex()); |
| | | assertNull(attributeIndex.getOrderingIndex()); |
| | | assertNotNull(attributeIndex.getApproximateIndex()); |
| | | List<DatabaseContainer> databases = new ArrayList<DatabaseContainer>(); |
| | | ec.listDatabases(databases); |
| | | assertFalse(findContainer(databases, "givenname.equality")); |
| | | assertFalse(findContainer(databases, "givenname.presence")); |
| | | assertFalse(findContainer(databases, "givenname.substring")); |
| | | assertFalse(findContainer(databases, "givenname.ordering")); |
| | | assertTrue(findContainer(databases, "givenname.approximate")); |
| | | Collection<String> containerNames = getContainerNames(ec); |
| | | assertThat(containerNames).doesNotContain( |
| | | indexName(ec, givenName, EMR_CASE_IGNORE_NAME), |
| | | indexName(ec, givenName, "presence"), |
| | | indexName(ec, givenName, substringIndexId()), |
| | | indexName(ec, givenName, OMR_CASE_IGNORE_NAME)); |
| | | assertThat(containerNames).contains(indexName(ec, givenName, AMR_DOUBLE_METAPHONE_NAME)); |
| | | |
| | | final SearchRequest request = newSearchRequest("dc=test,dc=com", SearchScope.SUBORDINATES, "(givenName~=Aaccf)") |
| | | .addAttribute(ATTR_DEBUG_SEARCH_INDEX); |
| | |
| | | assertThat(debugString).contains("not-indexed"); |
| | | |
| | | resultCode = TestCaseUtils.applyModifications(true, |
| | | "dn: ds-cfg-attribute=givenName,cn=Index," + |
| | | "ds-cfg-backend-id=indexRoot,cn=Backends,cn=config", |
| | | "dn: ds-cfg-attribute=givenName,cn=Index, ds-cfg-backend-id=indexRoot,cn=Backends,cn=config", |
| | | "changetype: modify", |
| | | "replace: ds-cfg-index-type", |
| | | "ds-cfg-index-type: equality", |
| | |
| | | |
| | | assertEquals(resultCode, 0); |
| | | |
| | | assertNotNull(attributeIndex.getEqualityIndex()); |
| | | assertNotNull(attributeIndex.getPresenceIndex()); |
| | | assertNotNull(attributeIndex.getSubstringIndex()); |
| | | assertNotNull(attributeIndex.getOrderingIndex()); |
| | | assertNull(attributeIndex.getApproximateIndex()); |
| | | databases = new ArrayList<DatabaseContainer>(); |
| | | ec.listDatabases(databases); |
| | | assertTrue(findContainer(databases, "givenname.equality")); |
| | | assertTrue(findContainer(databases, "givenname.presence")); |
| | | assertTrue(findContainer(databases, "givenname.substring")); |
| | | assertTrue(findContainer(databases, "givenname.ordering")); |
| | | assertFalse(findContainer(databases, "givenname.approximate")); |
| | | containerNames = getContainerNames(ec); |
| | | assertThat(containerNames).contains( |
| | | indexName(ec, givenName, EMR_CASE_IGNORE_NAME), |
| | | indexName(ec, givenName, "presence"), |
| | | indexName(ec, givenName, substringIndexId())); |
| | | // Ordering is also handled by equality since OPENDJ-1864 |
| | | assertThat(containerNames).doesNotContain( |
| | | indexName(ec, givenName, OMR_CASE_IGNORE_NAME), |
| | | indexName(ec, givenName, AMR_DOUBLE_METAPHONE_NAME)); |
| | | |
| | | // Delete the entries attribute index. |
| | | resultCode = TestCaseUtils.applyModifications(true, |
| | |
| | | |
| | | assertEquals(resultCode, 0); |
| | | |
| | | AttributeType givennameAttr = DirectoryServer.getAttributeType("givenname"); |
| | | assertNull(ec.getAttributeIndex(givennameAttr)); |
| | | databases = new ArrayList<DatabaseContainer>(); |
| | | |
| | | List<DatabaseContainer> databases = new ArrayList<>(); |
| | | ec.listDatabases(databases); |
| | | for(DatabaseContainer dc : databases) |
| | | { |
| | |
| | | assertEquals(resultCode, 0); |
| | | |
| | | assertNotNull(ec.getAttributeIndex(givennameAttr)); |
| | | databases = new ArrayList<DatabaseContainer>(); |
| | | ec.listDatabases(databases); |
| | | assertTrue(findContainer(databases, "givenname.equality")); |
| | | assertTrue(findContainer(databases, "givenname.presence")); |
| | | assertTrue(findContainer(databases, "givenname.substring")); |
| | | assertTrue(findContainer(databases, "givenname.ordering")); |
| | | assertFalse(findContainer(databases, "givenname.approximate")); |
| | | |
| | | containerNames = getContainerNames(ec); |
| | | assertThat(containerNames).contains( |
| | | indexName(ec, givenName, EMR_CASE_IGNORE_NAME), |
| | | indexName(ec, givenName, "presence"), |
| | | indexName(ec, givenName, substringIndexId())); |
| | | // Equality and Ordering indexes share the same database since OPENDJ-1864 |
| | | assertThat(containerNames).doesNotContain( |
| | | indexName(ec, givenName, OMR_CASE_IGNORE_NAME), |
| | | indexName(ec, givenName, AMR_DOUBLE_METAPHONE_NAME)); |
| | | |
| | | // Make sure changing the index entry limit on an index where the limit |
| | | // is already exceeded causes warnings. |
| | |
| | | assertEquals(resultCode, 0); |
| | | } |
| | | |
| | | private static boolean findContainer(List<DatabaseContainer> databases, String lowercaseName) |
| | | private static Collection<String> getContainerNames(EntryContainer container) |
| | | { |
| | | final List<DatabaseContainer> databases = new ArrayList<>(); |
| | | container.listDatabases(databases); |
| | | final Collection<String> names = new ArrayList<>(databases.size()); |
| | | for (DatabaseContainer dc : databases) |
| | | { |
| | | if (dc.getName().toLowerCase().contains(lowercaseName)) |
| | | { |
| | | return true; |
| | | } |
| | | names.add(dc.getName().toLowerCase()); |
| | | } |
| | | return false; |
| | | return names; |
| | | } |
| | | |
| | | private static Collection<String> getIndexNames(AttributeIndex index) |
| | | { |
| | | final Collection<String> names = new ArrayList<>(); |
| | | for (Index idx : index.getAllIndexes()) |
| | | { |
| | | names.add(idx.getName().toLowerCase()); |
| | | } |
| | | return names; |
| | | } |
| | | |
| | | private static String indexName(EntryContainer entryContainer, AttributeType attrType, String indexID) |
| | | { |
| | | return entryContainer.getDatabasePrefix() + "_" + attrType.getPrimaryName().toLowerCase() + "." + indexID.toLowerCase(); |
| | | } |
| | | |
| | | @Test(dependsOnMethods = {"testDeleteEntry", "testSearchScope", |
| | |
| | | } |
| | | } |
| | | |
| | | private static String substringIndexId() { |
| | | return SMR_CASE_IGNORE_NAME + ":" + getOptions().substringKeySize(); |
| | | } |
| | | |
| | | } |
| | |
| | | */ |
| | | package org.opends.server.backends.jeb; |
| | | |
| | | import static org.opends.server.schema.SchemaConstants.*; |
| | | import static org.opends.server.util.ServerConstants.*; |
| | | import static org.testng.Assert.*; |
| | | |
| | |
| | | @SuppressWarnings("javadoc") |
| | | public class TestVerifyJob extends JebTestCase |
| | | { |
| | | |
| | | private static final String EQUALITY_CASE_IGNORE = EMR_CASE_IGNORE_NAME; |
| | | private static final String EQUALITY_TELEPHONE = EMR_TELEPHONE_NAME; |
| | | private static final String ORDERING_CASE_IGNORE = OMR_CASE_IGNORE_NAME; |
| | | private static final String SUBSTRING_CASE_IGNORE_IA5 = SMR_CASE_IGNORE_IA5_NAME; |
| | | |
| | | /** Root suffix for verify backend. */ |
| | | private static String suffix="dc=verify,dc=jeb"; |
| | | private static String vBranch="ou=verify tests," + suffix; |
| | |
| | | try |
| | | { |
| | | AttributeType attributeType = DirectoryServer.getAttributeType(phoneType); |
| | | Index index = eContainer.getAttributeIndex(attributeType).getEqualityIndex(); |
| | | Index index = eContainer.getAttributeIndex(attributeType).getIndex(EQUALITY_TELEPHONE); |
| | | //Add entry with bad JEB format Version |
| | | addID2EntryReturnKey(junkDN, 4, true); |
| | | //Add phone number with various bad id list entryIDs |
| | |
| | | DirectoryServer.getAttributeType(mailType); |
| | | //Get db handles to each index. |
| | | AttributeIndex attributeIndex = eContainer.getAttributeIndex(attributeType); |
| | | Index eqIndex = attributeIndex.getEqualityIndex(); |
| | | Index presIndex = attributeIndex.getPresenceIndex(); |
| | | Index subIndex = attributeIndex.getSubstringIndex(); |
| | | Index ordIndex = attributeIndex.getOrderingIndex(); |
| | | Index eqIndex = attributeIndex.getIndex(EQUALITY_CASE_IGNORE); |
| | | Index presIndex = attributeIndex.getIndex("presence"); |
| | | Index subIndex = attributeIndex.getIndex(SUBSTRING_CASE_IGNORE_IA5 + ":6"); |
| | | // Ordering is processed by equality since OPENDJ-1864 |
| | | assertNull(attributeIndex.getIndex(ORDERING_CASE_IGNORE)); |
| | | |
| | | //Add invalid idlist ids to both equality and ordering indexes. |
| | | DatabaseEntry key= |
| | | new DatabaseEntry(StaticUtils.getBytes("user.0@example.com")); |
| | |
| | | DatabaseEntry data= new DatabaseEntry(dataBytes); |
| | | OperationStatus status = eqIndex.put(txn, key, data); |
| | | assertEquals(status, OperationStatus.SUCCESS); |
| | | status = ordIndex.put(txn, key, data); |
| | | assertEquals(status, OperationStatus.SUCCESS); |
| | | //Add null idlist to both equality and ordering indexes. |
| | | //Add null idlist to equality index. |
| | | key = new DatabaseEntry(StaticUtils.getBytes("user.1@example.com")); |
| | | data= new DatabaseEntry(new EntryIDSet().toDatabase()); |
| | | status = eqIndex.put(txn, key, data); |
| | | assertEquals(status, OperationStatus.SUCCESS); |
| | | status = ordIndex.put(txn, key, data); |
| | | assertEquals(status, OperationStatus.SUCCESS); |
| | | //Add invalid idlist ids to presence index. |
| | | key = new DatabaseEntry(StaticUtils.getBytes("+")); |
| | | data = new DatabaseEntry(dataBytes); |
| | |
| | | data = new DatabaseEntry(dataBytes); |
| | | status = subIndex.put(txn, key, data); |
| | | assertEquals(status, OperationStatus.SUCCESS); |
| | | performBECompleteVerify(mailType, 6); |
| | | performBECompleteVerify(mailType, 5); |
| | | } |
| | | finally |
| | | { |