From 2f28c948c02c1b3bb7961565e1d64a1684bc018c Mon Sep 17 00:00:00 2001
From: sin <sin@localhost>
Date: Sat, 31 Jan 2009 07:06:11 +0000
Subject: [PATCH] Integrating the changes related to Collation indexing support
---
opendj-sdk/opends/src/server/org/opends/server/api/ExtensibleMatchingRule.java | 34
opendj-sdk/opends/src/server/org/opends/server/admin/PropertyDefinitionUsageBuilder.java | 13
opendj-sdk/opends/src/server/org/opends/server/core/DirectoryServer.java | 38
opendj-sdk/opends/src/server/org/opends/server/types/Schema.java | 199 ++
opendj-sdk/opends/src/server/org/opends/server/backends/jeb/IndexFilter.java | 33
opendj-sdk/opends/resource/admin/property-types.xsl | 3
opendj-sdk/opends/resource/admin/property-types/extensible-matching-rule-type.xsl | 42
opendj-sdk/opends/src/server/org/opends/server/backends/jeb/AttributeIndex.java | 711 ++++++++++
opendj-sdk/opends/src/server/org/opends/server/admin/ExtensibleMatchingRuleTypePropertyDefinition.java | 185 ++
opendj-sdk/opends/src/server/org/opends/server/admin/PropertyValueVisitor.java | 22
opendj-sdk/opends/src/admin/defn/org/opends/server/admin/std/LocalDBIndexConfiguration.xml | 41
opendj-sdk/opends/src/server/org/opends/server/backends/jeb/IndexQuery.java | 209 +++
opendj-sdk/opends/src/server/org/opends/server/types/IndexConfig.java | 41
opendj-sdk/opends/src/server/org/opends/server/backends/jeb/BackendImpl.java | 24
opendj-sdk/opends/src/server/org/opends/server/api/IndexQueryFactory.java | 118 +
opendj-sdk/opends/resource/admin/admin.xsd | 8
opendj-sdk/opends/src/server/org/opends/server/schema/CollationMatchingRuleFactory.java | 1802 ++++++++++++++-----------
opendj-sdk/opends/src/server/org/opends/server/backends/jeb/JEExtensibleIndexer.java | 221 +++
opendj-sdk/opends/src/server/org/opends/server/backends/jeb/IndexQueryFactoryImpl.java | 152 ++
opendj-sdk/opends/src/server/org/opends/server/backends/jeb/importLDIF/WorkThread.java | 31
opendj-sdk/opends/src/server/org/opends/server/util/ServerConstants.java | 18
opendj-sdk/opends/src/server/org/opends/server/api/ExtensibleIndexer.java | 92 +
opendj-sdk/opends/resource/schema/02-config.ldif | 7
opendj-sdk/opends/src/server/org/opends/server/admin/PropertyDefinitionVisitor.java | 19
24 files changed, 3,227 insertions(+), 836 deletions(-)
diff --git a/opendj-sdk/opends/resource/admin/admin.xsd b/opendj-sdk/opends/resource/admin/admin.xsd
index 121c9fd..ace9c9c 100644
--- a/opendj-sdk/opends/resource/admin/admin.xsd
+++ b/opendj-sdk/opends/resource/admin/admin.xsd
@@ -1330,6 +1330,14 @@
</xsd:annotation>
<xsd:complexType />
</xsd:element>
+ <xsd:element name="extensible-matching-rule-type">
+ <xsd:annotation>
+ <xsd:documentation>
+ Used for properties which contain Extensible matching rule type names.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:complexType />
+ </xsd:element>
<xsd:element name="boolean">
<xsd:annotation>
<xsd:documentation>
diff --git a/opendj-sdk/opends/resource/admin/property-types.xsl b/opendj-sdk/opends/resource/admin/property-types.xsl
index 0c2f5f5..b32a657 100644
--- a/opendj-sdk/opends/resource/admin/property-types.xsl
+++ b/opendj-sdk/opends/resource/admin/property-types.xsl
@@ -22,7 +22,7 @@
! CDDL HEADER END
!
!
- ! Copyright 2008 Sun Microsystems, Inc.
+ ! Copyright 2008-2009 Sun Microsystems, Inc.
! -->
<xsl:stylesheet version="1.0" xmlns:adm="http://www.opends.org/admin"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
@@ -54,6 +54,7 @@
<xsl:include href="property-types/password.xsl" />
<xsl:include href="property-types/size.xsl" />
<xsl:include href="property-types/string.xsl" />
+ <xsl:include href="property-types/extensible-matching-rule-type.xsl" />
<!--
diff --git a/opendj-sdk/opends/resource/admin/property-types/extensible-matching-rule-type.xsl b/opendj-sdk/opends/resource/admin/property-types/extensible-matching-rule-type.xsl
new file mode 100644
index 0000000..60cf61c
--- /dev/null
+++ b/opendj-sdk/opends/resource/admin/property-types/extensible-matching-rule-type.xsl
@@ -0,0 +1,42 @@
+<!--
+ ! CDDL HEADER START
+ !
+ ! The contents of this file are subject to the terms of the
+ ! Common Development and Distribution License, Version 1.0 only
+ ! (the "License"). You may not use this file except in compliance
+ ! with the License.
+ !
+ ! You can obtain a copy of the license at
+ ! trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ ! or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ ! See the License for the specific language governing permissions
+ ! and limitations under the License.
+ !
+ ! When distributing Covered Code, include this CDDL HEADER in each
+ ! file and include the License file at
+ ! trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
+ ! add the following below this CDDL HEADER, with the fields enclosed
+ ! by brackets "[]" replaced with your own identifying information:
+ ! Portions Copyright [yyyy] [name of copyright owner]
+ !
+ ! CDDL HEADER END
+ !
+ !
+ ! Copyright 2009 Sun Microsystems, Inc.
+ ! -->
+<xsl:stylesheet version="1.0" xmlns:adm="http://www.opends.org/admin"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+ <!--
+ Templates for processing extensible matching rule type properties.
+ -->
+ <xsl:template match="adm:extensible-matching-rule-type" mode="java-value-imports">
+ <import>org.opends.server.api.ExtensibleMatchingRule</import>
+ </xsl:template>
+ <xsl:template match="adm:extensible-matching-rule-type" mode="java-value-type">
+ <xsl:value-of select="'ExtensibleMatchingRule'" />
+ </xsl:template>
+ <xsl:template match="adm:extensible-matching-rule-type"
+ mode="java-definition-type">
+ <xsl:value-of select="'ExtensibleMatchingRuleTypePropertyDefinition'" />
+ </xsl:template>
+</xsl:stylesheet>
diff --git a/opendj-sdk/opends/resource/schema/02-config.ldif b/opendj-sdk/opends/resource/schema/02-config.ldif
index bb2b9f1..93aafcb 100644
--- a/opendj-sdk/opends/resource/schema/02-config.ldif
+++ b/opendj-sdk/opends/resource/schema/02-config.ldif
@@ -2387,6 +2387,10 @@
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
SINGLE-VALUE
X-ORIGIN 'OpenDS Directory Server' )
+attributeTypes: ( 1.3.6.1.4.1.26027.1.1.518
+ NAME 'ds-cfg-index-extensible-matching-rule'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
+ X-ORIGIN 'OpenDS Directory Server' )
objectClasses: ( 1.3.6.1.4.1.26027.1.2.1
NAME 'ds-cfg-access-control-handler'
SUP top
@@ -2465,7 +2469,8 @@
MUST ( ds-cfg-attribute $
ds-cfg-index-type )
MAY ( ds-cfg-index-entry-limit $
- ds-cfg-substring-length )
+ ds-cfg-substring-length $
+ ds-cfg-index-extensible-matching-rule )
X-ORIGIN 'OpenDS Directory Server' )
objectClasses: ( 1.3.6.1.4.1.26027.1.2.8
NAME 'ds-cfg-schema-backend'
diff --git a/opendj-sdk/opends/src/admin/defn/org/opends/server/admin/std/LocalDBIndexConfiguration.xml b/opendj-sdk/opends/src/admin/defn/org/opends/server/admin/std/LocalDBIndexConfiguration.xml
index 187669e..cfb2ad9 100644
--- a/opendj-sdk/opends/src/admin/defn/org/opends/server/admin/std/LocalDBIndexConfiguration.xml
+++ b/opendj-sdk/opends/src/admin/defn/org/opends/server/admin/std/LocalDBIndexConfiguration.xml
@@ -23,7 +23,7 @@
! CDDL HEADER END
!
!
- ! Copyright 2007-2008 Sun Microsystems, Inc.
+ ! Copyright 2007-2009 Sun Microsystems, Inc.
! -->
<adm:managed-object name="local-db-index" plural-name="local-db-indexes"
package="org.opends.server.admin.std"
@@ -110,7 +110,7 @@
<adm:requires-admin-action>
<adm:other>
<adm:synopsis>
- If any new index types are added for an attribute, and
+ If any new index types are added for an attribute, and
values for that attribute already exist in the
database, the index must be rebuilt before it
will be accurate.
@@ -150,6 +150,12 @@
of searches using approximate matching search filters.
</adm:synopsis>
</adm:value>
+ <adm:value name="extensible">
+ <adm:synopsis>
+ This index type is used to improve the efficiency
+ of searches using extensible matching search filters.
+ </adm:synopsis>
+ </adm:value>
</adm:enumeration>
</adm:syntax>
<adm:profile name="ldap">
@@ -184,4 +190,35 @@
</ldap:attribute>
</adm:profile>
</adm:property>
+ <adm:property name="index-extensible-matching-rule" multi-valued="true">
+ <adm:synopsis>
+ The extensible matching rule in an extensible index.
+ </adm:synopsis>
+ <adm:description>
+ An extensible matching rule must be specified using either LOCALE or OID of the matching rule.
+ </adm:description>
+ <adm:requires-admin-action>
+ <adm:other>
+ <adm:synopsis>
+ The index must be rebuilt before it will reflect the
+ new value.
+ </adm:synopsis>
+ </adm:other>
+ </adm:requires-admin-action>
+ <adm:default-behavior>
+ <adm:alias>
+ <adm:synopsis>
+ No extensible matching rules will be indexed.
+ </adm:synopsis>
+ </adm:alias>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:extensible-matching-rule-type/>
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:name>ds-cfg-index-extensible-matching-rule</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
</adm:managed-object>
diff --git a/opendj-sdk/opends/src/server/org/opends/server/admin/ExtensibleMatchingRuleTypePropertyDefinition.java b/opendj-sdk/opends/src/server/org/opends/server/admin/ExtensibleMatchingRuleTypePropertyDefinition.java
new file mode 100644
index 0000000..25dbde0
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/admin/ExtensibleMatchingRuleTypePropertyDefinition.java
@@ -0,0 +1,185 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ * Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ * Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.server.admin;
+
+import java.util.EnumSet;
+import org.opends.server.api.ExtensibleMatchingRule;
+
+import org.opends.server.core.DirectoryServer;
+import static org.opends.server.util.Validator.ensureNotNull;
+
+/**
+ * Extensible Matching Rule Type Propertiy Definition.
+ */
+public final class ExtensibleMatchingRuleTypePropertyDefinition
+ extends PropertyDefinition<ExtensibleMatchingRule>
+{
+
+ /**
+ * An interface for incrementally constructing attribute type
+ * property definitions.
+ */
+ public static class Builder extends
+ AbstractBuilder<ExtensibleMatchingRule,
+ ExtensibleMatchingRuleTypePropertyDefinition> {
+
+ // Private constructor
+ private Builder(AbstractManagedObjectDefinition<?, ?> d,
+ String propertyName) {
+ super(d, propertyName);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected ExtensibleMatchingRuleTypePropertyDefinition buildInstance(
+ AbstractManagedObjectDefinition<?, ?> d, String propertyName,
+ EnumSet<PropertyOption> options,
+ AdministratorAction adminAction,
+ DefaultBehaviorProvider<ExtensibleMatchingRule> defaultBehavior) {
+ return new ExtensibleMatchingRuleTypePropertyDefinition(d, propertyName,
+ options, adminAction, defaultBehavior);
+ }
+ }
+
+
+ /**
+ * Create an extensible matching rule type property definition builder.
+ *
+ * @param d
+ * The managed object definition associated with this
+ * property definition.
+ * @param propertyName
+ * The property name.
+ * @return Returns the new attribute type property definition
+ * builder.
+ */
+ public static Builder createBuilder(
+ AbstractManagedObjectDefinition<?, ?> d, String propertyName) {
+ return new Builder(d, propertyName);
+ }
+
+
+
+ /**
+ * Creates a new insantce of this class.
+ */
+ private ExtensibleMatchingRuleTypePropertyDefinition(
+ AbstractManagedObjectDefinition<?, ?> d, String propertyName,
+ EnumSet<PropertyOption> options,
+ AdministratorAction adminAction,
+ DefaultBehaviorProvider<ExtensibleMatchingRule> defaultBehavior) {
+ super(d, ExtensibleMatchingRule.class, propertyName, options,
+ adminAction, defaultBehavior);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public <R, P> R accept(PropertyDefinitionVisitor<R, P> v, P p) {
+ return v.visitExtensibleMatchingRuleType(this, p);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public <R, P> R accept(PropertyValueVisitor<R, P> v,
+ ExtensibleMatchingRule value, P p) {
+ return v.visitExtensibleMatchingRuleType(this, value, p);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int compare(ExtensibleMatchingRule o1, ExtensibleMatchingRule o2) {
+ return o1.getOID().compareToIgnoreCase(o2.getOID());
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public ExtensibleMatchingRule decodeValue(String value)
+ throws IllegalPropertyValueStringException {
+ ensureNotNull(value);
+
+ String name = value.trim().toLowerCase();
+ //Check if the name is a valid Matching rule OID or a Locale value.
+ ExtensibleMatchingRule rule =
+ DirectoryServer.getExtensibleMatchingRule(name);
+
+ if (rule == null) {
+ throw new IllegalPropertyValueStringException(this, value);
+ } else {
+ try {
+ validateValue(rule);
+ return rule;
+ } catch (IllegalPropertyValueException e) {
+ throw new IllegalPropertyValueStringException(this, value);
+ }
+ }
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String encodeValue(ExtensibleMatchingRule value)
+ throws IllegalPropertyValueException {
+ return value.getNameOrOID();
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void validateValue(ExtensibleMatchingRule value)
+ throws IllegalPropertyValueException {
+ ensureNotNull(value);
+
+ // No implementation required.
+ }
+}
\ No newline at end of file
diff --git a/opendj-sdk/opends/src/server/org/opends/server/admin/PropertyDefinitionUsageBuilder.java b/opendj-sdk/opends/src/server/org/opends/server/admin/PropertyDefinitionUsageBuilder.java
index 6af6cff..ee38963 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/admin/PropertyDefinitionUsageBuilder.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/admin/PropertyDefinitionUsageBuilder.java
@@ -22,7 +22,7 @@
* CDDL HEADER END
*
*
- * Copyright 2008 Sun Microsystems, Inc.
+ * Copyright 2008-2009 Sun Microsystems, Inc.
*/
package org.opends.server.admin;
import org.opends.messages.Message;
@@ -338,6 +338,17 @@
* {@inheritDoc}
*/
@Override
+ public Message visitExtensibleMatchingRuleType(
+ ExtensibleMatchingRuleTypePropertyDefinition d, Void p) {
+ return Message.raw("LOCALE | OID");
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
public <T> Message visitUnknown(PropertyDefinition<T> d, Void p)
throws UnknownPropertyDefinitionException {
return Message.raw("?");
diff --git a/opendj-sdk/opends/src/server/org/opends/server/admin/PropertyDefinitionVisitor.java b/opendj-sdk/opends/src/server/org/opends/server/admin/PropertyDefinitionVisitor.java
index fa728de..67ab9a9 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/admin/PropertyDefinitionVisitor.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/admin/PropertyDefinitionVisitor.java
@@ -22,7 +22,7 @@
* CDDL HEADER END
*
*
- * Copyright 2008 Sun Microsystems, Inc.
+ * Copyright 2008-2009 Sun Microsystems, Inc.
*/
package org.opends.server.admin;
@@ -268,6 +268,23 @@
+ /**
+ * Visit an extensible matching rule property definition.
+ *
+ * @param pd
+ * The string property definition to visit.
+ * @param p
+ * A visitor specified parameter.
+ * @return Returns a visitor specified result.
+ */
+ public R visitExtensibleMatchingRuleType(
+ ExtensibleMatchingRuleTypePropertyDefinition pd, P p) {
+ return visitUnknown(pd, p);
+ }
+
+
+
+
/**
* Visit an unknown type of property definition. Implementations of
* this method can provide default behavior for unknown property
diff --git a/opendj-sdk/opends/src/server/org/opends/server/admin/PropertyValueVisitor.java b/opendj-sdk/opends/src/server/org/opends/server/admin/PropertyValueVisitor.java
index 9293048..c7b42be 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/admin/PropertyValueVisitor.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/admin/PropertyValueVisitor.java
@@ -22,7 +22,7 @@
* CDDL HEADER END
*
*
- * Copyright 2008 Sun Microsystems, Inc.
+ * Copyright 2008-2009 Sun Microsystems, Inc.
*/
package org.opends.server.admin;
@@ -35,6 +35,7 @@
import org.opends.server.types.AttributeType;
import org.opends.server.types.DN;
import org.opends.server.authorization.dseecompat.Aci;
+import org.opends.server.api.ExtensibleMatchingRule;
/**
@@ -308,6 +309,25 @@
/**
+ * Visit an extensible matching rule type.
+ *
+ * @param pd
+ * The extensible matching rule type property definition.
+ * @param v
+ * The property value to visit.
+ * @param p
+ * A visitor specified parameter.
+ * @return Returns a visitor specified result.
+ */
+ public R visitExtensibleMatchingRuleType(
+ ExtensibleMatchingRuleTypePropertyDefinition pd,
+ ExtensibleMatchingRule v, P p) {
+ return visitUnknown(pd, v, p);
+ }
+
+
+
+ /**
* Visit an unknown type of property value. Implementations of this
* method can provide default behavior for unknown types of
* property.
diff --git a/opendj-sdk/opends/src/server/org/opends/server/api/ExtensibleIndexer.java b/opendj-sdk/opends/src/server/org/opends/server/api/ExtensibleIndexer.java
new file mode 100644
index 0000000..47edcc2
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/api/ExtensibleIndexer.java
@@ -0,0 +1,92 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ * Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ * Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.server.api;
+
+import java.util.Map;
+import java.util.Set;
+import org.opends.server.types.AttributeValue;
+
+/**
+ * This class is registered with a Backend and it provides call-
+ * backs for indexing attribute values. An index implementation will
+ * use this interface to create the keys for an attribute value.
+ */
+@org.opends.server.types.PublicAPI(
+ stability=org.opends.server.types.StabilityLevel.VOLATILE,
+ mayInstantiate=false,
+ mayExtend=true,
+ mayInvoke=false)
+public abstract class ExtensibleIndexer
+{
+ /**
+ * Returns the index name preferred by this indexer. This name
+ * appended with the identifier returned from
+ * {@link #getExtensibleIndexID()} will be used as the index
+ * database name.
+ * @return The name of the index for this indexer.
+ */
+ public abstract String getPreferredIndexName();
+
+
+ /**
+ * Returns an index identifier associated with this indexer. An
+ * identifier should be selected based on the matching rule type.
+ * A unique identifier will map to a unique index database in
+ * the backend implementation. If multiple matching rules
+ * need to share the index database, the corresponding indexers
+ * should always use the same identifier.
+ * @return index ID A String containing the ID associated with
+ * this indexer.
+ */
+ public abstract String getExtensibleIndexID();
+
+
+ /**
+ * Generates the set of index keys for an attribute.
+ * @param value The attribute value for which keys are required.
+ * @param keys The set into which the generated keys will be
+ * inserted.
+ */
+ public abstract void getKeys(AttributeValue value,
+ Set<byte[]> keys);
+
+
+ /**
+ * Generates a map of index keys and a boolean flag indicating
+ * whether the corresponding key will be inserted or deleted.
+ * @param value The attribute for which keys are required.
+ * @param modifiedKeys A map containing the keys and a boolean.
+ * Keys corresponding to the boolean value <code>true
+ * </code> should be inserted and <code>false</code>
+ * should be deleted.
+ * @param insert <code>true</code> if generated keys should
+ * be inserted or <code>false</code> otherwise.
+ */
+ public abstract void getKeys(AttributeValue value,
+ Map<byte[], Boolean> modifiedKeys,
+ Boolean insert);
+}
\ No newline at end of file
diff --git a/opendj-sdk/opends/src/server/org/opends/server/api/ExtensibleMatchingRule.java b/opendj-sdk/opends/src/server/org/opends/server/api/ExtensibleMatchingRule.java
index 6b25a58..798da0d 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/api/ExtensibleMatchingRule.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/api/ExtensibleMatchingRule.java
@@ -22,10 +22,14 @@
* CDDL HEADER END
*
*
- * Copyright 2008 Sun Microsystems, Inc.
+ * Copyright 2008-2009 Sun Microsystems, Inc.
*/
package org.opends.server.api;
+import java.util.Collection;
+import org.opends.server.types.ByteString;
+import org.opends.server.types.DirectoryException;
+import org.opends.server.types.IndexConfig;
/**
@@ -40,7 +44,33 @@
mayInvoke=false)
public abstract class ExtensibleMatchingRule extends MatchingRule
{
+ /**
+ * Returns a collection of extensible indexers associated with this
+ * matching rule.
+ * @param config The index configuration to be used by this
+ * matching rule.
+ * @return ExtensibleIndexer associated with this matching rule.
+ */
+ public abstract Collection<ExtensibleIndexer> getIndexers(
+ IndexConfig config);
- //TODO: Index Implementation.
+
+
+ /**
+ * Queries the index using factory of type T and returns
+ * a query of type T for the provided assertion value.
+ * @param <T> The type of IndexQueryFactory.
+ * @param assertionValue An assertion value which needs to be
+ * queried.
+ * @param factory An IndexQueryFactory which will be used for
+ * creating queries.
+ * @return T The generated index query.
+ * @throws DirectoryException If an error occurs while generating
+ * the query.
+ */
+ public abstract <T> T createIndexQuery(
+ ByteString assertionValue,
+ IndexQueryFactory<T> factory)
+ throws DirectoryException;
}
\ No newline at end of file
diff --git a/opendj-sdk/opends/src/server/org/opends/server/api/IndexQueryFactory.java b/opendj-sdk/opends/src/server/org/opends/server/api/IndexQueryFactory.java
new file mode 100644
index 0000000..a4f173d
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/api/IndexQueryFactory.java
@@ -0,0 +1,118 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ * Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ * Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.server.api;
+
+import java.util.Collection;
+
+/**
+ * This class acts as a factory for creating index queries. This
+ * interface is implemented by the underlying backend implementation
+ * and passed to extensible matching rules so that they can construct
+ * arbitrarily complex index queries.
+ *
+ * @param <T> The type of Results returned by the factory.
+ */
+@org.opends.server.types.PublicAPI(
+ stability=org.opends.server.types.StabilityLevel.VOLATILE,
+ mayInstantiate=false,
+ mayExtend=true,
+ mayInvoke=false)
+public interface IndexQueryFactory<T>
+{
+
+ /**
+ * Returns a query requesting an index record matching the
+ * provided key.
+ * @param indexID An identifier of the index type.
+ * @param key A byte array containing the key.
+ * @return A query requesting the index record matching the key.
+ */
+ T createExactMatchQuery(String indexID,byte[] key);
+
+
+
+ /**
+ * Returns a query requesting all index records. A backend
+ * implementation may choose to return all or no records as
+ * part of the optimization.
+ * @return A query requesting all index records.
+ */
+ T createMatchAllQuery();
+
+
+
+ /**
+ * Rreturns a query requesting all index records in the specified
+ * range.
+ * @param indexID An identifier of the index type.
+ * @param lower The lower bound of the range. A 0 length byte
+ * array indicates no lower bound and the
+ * range will start from the smallest key.
+ * @param upper The upper bound of the range. A 0 length byte array
+ * indicates no upper bound and the range will
+ * end at the largest key.
+ * @param lowerIncluded true if a key exactly matching the lower
+ * bound is included in the range, false if
+ * only keys strictly greater than the lower
+ * bound are included.This value is ignored if
+ * the lower bound is not specified.
+ * @param upperIncluded true if a key exactly matching the upper
+ * bound is included in the range, false if
+ * only keys strictly less than the upper
+ * bound are included. This value is ignored if
+ * the upper bound is not specified.
+ * @return A query requesting all index records in the specified
+ * range.
+ */
+ T createRangeMatchQuery(
+ String indexID,
+ byte[] lower,
+ byte[] upper,
+ boolean lowerIncluded,
+ boolean upperIncluded);
+
+
+
+ /**
+ * Returns a query requesting intersection from a Collection of
+ * sub-queries.
+ *@param subquery A Collection of sub-queries.
+ *@return A query requesting intersection of the records.
+ */
+ T createIntersectionQuery(Collection<T> subquery);
+
+
+
+
+ /**
+ * Returns a query requesting union from a Collection of
+ * sub-queries.
+ * @param subquery A Collection of sub-queries.
+ * @return A query requesting union of the records.
+ */
+ T createUnionQuery(Collection<T> subquery);
+}
\ No newline at end of file
diff --git a/opendj-sdk/opends/src/server/org/opends/server/backends/jeb/AttributeIndex.java b/opendj-sdk/opends/src/server/org/opends/server/backends/jeb/AttributeIndex.java
index 6b90b13..75fe149 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/backends/jeb/AttributeIndex.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/backends/jeb/AttributeIndex.java
@@ -22,7 +22,7 @@
* CDDL HEADER END
*
*
- * Copyright 2006-2008 Sun Microsystems, Inc.
+ * Copyright 2006-2009 Sun Microsystems, Inc.
*/
package org.opends.server.backends.jeb;
import org.opends.messages.Message;
@@ -42,8 +42,12 @@
import org.opends.server.admin.std.server.LocalDBIndexCfg;
import org.opends.server.admin.std.meta.LocalDBIndexCfgDefn;
import org.opends.server.admin.server.ConfigurationChangeListener;
+import org.opends.server.api.ExtensibleIndexer;
+import org.opends.server.api.ExtensibleMatchingRule;
+import org.opends.server.api.IndexQueryFactory;
import org.opends.server.config.ConfigException;
import static org.opends.messages.JebMessages.*;
+import static org.opends.server.util.ServerConstants.*;
import org.opends.server.core.DirectoryServer;
import org.opends.server.util.StaticUtils;
@@ -113,6 +117,12 @@
*/
Index approximateIndex = null;
+ /**
+ * The ExtensibleMatchingRuleIndex instance for ExtensibleMatchingRule
+ * indexes.
+ */
+ private ExtensibleMatchingRuleIndex extensibleIndexes = null;
+
private State state;
private int cursorEntryLimit = 100000;
@@ -238,7 +248,61 @@
env,
entryContainer);
}
-
+ if (indexConfig.getIndexType().contains(
+ LocalDBIndexCfgDefn.IndexType.EXTENSIBLE))
+ {
+ Set<ExtensibleMatchingRule> extensibleRules =
+ indexConfig.getIndexExtensibleMatchingRule();
+ if(extensibleRules == null || extensibleRules.size() == 0)
+ {
+ Message message = ERR_CONFIG_INDEX_TYPE_NEEDS_MATCHING_RULE.get(
+ String.valueOf(attrType), "extensible");
+ throw new ConfigException(message);
+ }
+ extensibleIndexes = new ExtensibleMatchingRuleIndex();
+ //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.
+ IndexConfig config = new JEIndexConfig(indexConfig.getSubstringLength());
+ for(ExtensibleMatchingRule rule:extensibleRules)
+ {
+ Map<String,Index> indexMap = new HashMap<String,Index>();
+ for(ExtensibleIndexer indexer : rule.getIndexers(config))
+ {
+ String indexerId = indexer.getExtensibleIndexID();
+ String indexID =
+ attrType.getNameOrOID() + "."
+ + indexer.getPreferredIndexName()
+ + "." + indexerId;
+ if(!extensibleIndexes.isIndexPresent(indexID))
+ {
+ //There is no index available for this index id. Create a new index.
+ Indexer extensibleIndexer =
+ new JEExtensibleIndexer(attrType,
+ rule,
+ indexer);
+ String indexName = entryContainer.getDatabasePrefix() + "_"
+ + indexID;
+ Index extensibleIndex = new Index(indexName,
+ extensibleIndexer,
+ state,
+ indexEntryLimit,
+ cursorEntryLimit,
+ false,
+ env,
+ entryContainer);
+ extensibleIndexes.addIndex(extensibleIndex,indexID);
+ }
+ extensibleIndexes.addRule(indexID, rule);
+ indexMap.put(indexer.getExtensibleIndexID(),
+ extensibleIndexes.getIndex(indexID));
+ }
+ IndexQueryFactory<IndexQuery> factory =
+ new IndexQueryFactoryImpl(indexMap);
+ extensibleIndexes.addQueryFactory(rule, factory);
+ }
+ }
this.indexConfig.addChangeListener(this);
}
@@ -274,6 +338,14 @@
{
approximateIndex.open();
}
+
+ if(extensibleIndexes!=null)
+ {
+ for(Index extensibleIndex:extensibleIndexes.getIndexes())
+ {
+ extensibleIndex.open();
+ }
+ }
}
/**
@@ -309,6 +381,14 @@
approximateIndex.close();
}
+ if(extensibleIndexes!=null)
+ {
+ for(Index extensibleIndex:extensibleIndexes.getIndexes())
+ {
+ extensibleIndex.close();
+ }
+ }
+
indexConfig.removeChangeListener(this);
// The entryContainer is responsible for closing the JE databases.
}
@@ -388,6 +468,17 @@
}
}
+ if(extensibleIndexes!=null)
+ {
+ for(Index extensibleIndex:extensibleIndexes.getIndexes())
+ {
+ if(!extensibleIndex.addEntry(buffer, entryID,entry))
+ {
+ success = false;
+ }
+ }
+ }
+
return success;
}
@@ -448,6 +539,17 @@
}
}
+ if(extensibleIndexes!=null)
+ {
+ for(Index extensibleIndex:extensibleIndexes.getIndexes())
+ {
+ if(!extensibleIndex.addEntry(txn, entryID,entry))
+ {
+ success = false;
+ }
+ }
+ }
+
return success;
}
@@ -488,6 +590,14 @@
{
approximateIndex.removeEntry(buffer, entryID, entry);
}
+
+ if(extensibleIndexes!=null)
+ {
+ for(Index extensibleIndex:extensibleIndexes.getIndexes())
+ {
+ extensibleIndex.removeEntry(buffer, entryID, entry);
+ }
+ }
}
/**
@@ -526,6 +636,14 @@
{
approximateIndex.removeEntry(txn, entryID, entry);
}
+
+ if(extensibleIndexes!=null)
+ {
+ for(Index extensibleIndex:extensibleIndexes.getIndexes())
+ {
+ extensibleIndex.removeEntry(txn, entryID, entry);
+ }
+ }
}
/**
@@ -571,6 +689,14 @@
{
approximateIndex.modifyEntry(txn, entryID, oldEntry, newEntry, mods);
}
+
+ if(extensibleIndexes!=null)
+ {
+ for(Index extensibleIndex:extensibleIndexes.getIndexes())
+ {
+ extensibleIndex.modifyEntry(txn, entryID, oldEntry, newEntry, mods);
+ }
+ }
}
/**
@@ -616,6 +742,14 @@
{
approximateIndex.modifyEntry(buffer, entryID, oldEntry, newEntry, mods);
}
+
+ if(extensibleIndexes!=null)
+ {
+ for(Index extensibleIndex:extensibleIndexes.getIndexes())
+ {
+ extensibleIndex.modifyEntry(buffer, entryID, oldEntry, newEntry, mods);
+ }
+ }
}
/**
@@ -1249,6 +1383,14 @@
{
approximateIndex.closeCursor();
}
+
+ if(extensibleIndexes!=null)
+ {
+ for(Index extensibleIndex:extensibleIndexes.getIndexes())
+ {
+ extensibleIndex.closeCursor();
+ }
+ }
}
/**
@@ -1287,6 +1429,14 @@
approximateIndex.getEntryLimitExceededCount();
}
+ if(extensibleIndexes!=null)
+ {
+ for(Index extensibleIndex:extensibleIndexes.getIndexes())
+ {
+ entryLimitExceededCount +=
+ extensibleIndex.getEntryLimitExceededCount();
+ }
+ }
return entryLimitExceededCount;
}
@@ -1320,6 +1470,14 @@
{
dbList.add(approximateIndex);
}
+
+ if(extensibleIndexes!=null)
+ {
+ for(Index extensibleIndex:extensibleIndexes.getIndexes())
+ {
+ dbList.add(extensibleIndex);
+ }
+ }
}
/**
@@ -1384,6 +1542,18 @@
return false;
}
}
+ if (cfg.getIndexType().contains(LocalDBIndexCfgDefn.IndexType.EXTENSIBLE))
+ {
+ Set<ExtensibleMatchingRule> newRules =
+ cfg.getIndexExtensibleMatchingRule();
+ if (newRules == null || newRules.size() == 0)
+ {
+ Message message = ERR_CONFIG_INDEX_TYPE_NEEDS_MATCHING_RULE.get(
+ String.valueOf(attrType), "extensible");
+ unacceptableReasons.add(message);
+ return false;
+ }
+ }
return true;
}
@@ -1721,6 +1891,171 @@
}
}
+ if (cfg.getIndexType().contains(
+ LocalDBIndexCfgDefn.IndexType.EXTENSIBLE))
+ {
+ Set<ExtensibleMatchingRule> extensibleRules =
+ cfg.getIndexExtensibleMatchingRule();
+ if(extensibleIndexes == null)
+ {
+ extensibleIndexes = new ExtensibleMatchingRuleIndex();
+ }
+ IndexConfig config = new JEIndexConfig(cfg.getSubstringLength());
+ for(ExtensibleMatchingRule rule:extensibleRules)
+ {
+ Map<String,Index> indexMap = new HashMap<String,Index>();
+ for(ExtensibleIndexer indexer: rule.getIndexers(config))
+ {
+ String indexerId = indexer.getExtensibleIndexID();
+ String indexID =
+ attrType.getNameOrOID() + "."
+ + indexer.getPreferredIndexName()
+ + "." + indexerId;
+ if(!extensibleIndexes.isIndexPresent(indexID))
+ {
+ Indexer extensibleIndexer =
+ new JEExtensibleIndexer(attrType,
+ rule,
+ indexer);
+ String indexName = entryContainer.getDatabasePrefix() + "_"
+ + indexID;
+ Index extensibleIndex = new Index(indexName,
+ extensibleIndexer,
+ state,
+ indexEntryLimit,
+ cursorEntryLimit,
+ false,
+ env,
+ entryContainer);
+ extensibleIndexes.addIndex(extensibleIndex,indexID);
+ }
+ else
+ {
+ Index extensibleIndex = extensibleIndexes.getIndex(indexID);
+ if(extensibleIndex.setIndexEntryLimit(indexEntryLimit))
+ {
+ adminActionRequired = true;
+ Message message =
+ NOTE_JEB_CONFIG_INDEX_ENTRY_LIMIT_REQUIRES_REBUILD.get(
+ extensibleIndex.getName());
+ messages.add(message);
+ }
+ if(indexConfig.getSubstringLength() !=
+ cfg.getSubstringLength())
+ {
+ Indexer extensibleIndexer =
+ new JEExtensibleIndexer(attrType,
+ rule,
+ indexer);
+ extensibleIndex.setIndexer(extensibleIndexer);
+ }
+ }
+ extensibleIndexes.addRule(indexID, rule);
+ indexMap.put(indexerId,extensibleIndexes.getIndex(indexID));
+ }
+ IndexQueryFactory<IndexQuery> factory =
+ new IndexQueryFactoryImpl(indexMap);
+ extensibleIndexes.addQueryFactory(rule, factory);
+ }
+ //Some rules might have been removed from the configuration.
+ Set<ExtensibleMatchingRule> deletedRules =
+ new HashSet<ExtensibleMatchingRule>();
+ for(ExtensibleMatchingRule r:extensibleIndexes.getRules())
+ {
+ if(!extensibleRules.contains(r))
+ {
+ deletedRules.add(r);
+ }
+ }
+ if(deletedRules.size() > 0)
+ {
+ entryContainer.exclusiveLock.lock();
+ try
+ {
+ for(ExtensibleMatchingRule rule:deletedRules)
+ {
+ Set<ExtensibleMatchingRule> rules =
+ new HashSet<ExtensibleMatchingRule>();
+ List<String> ids = new ArrayList<String>();
+ for(ExtensibleIndexer indexer: rule.getIndexers(config))
+ {
+ String id = attrType.getNameOrOID() + "."
+ + indexer.getPreferredIndexName()
+ + "." + indexer.getExtensibleIndexID();
+ rules.addAll(extensibleIndexes.getRules(id));
+ ids.add(id);
+ }
+ if(rules.isEmpty())
+ {
+ //Rule has been already deleted.
+ continue;
+ }
+ //If all the rules are part of the deletedRules, delete
+ //this index.
+ if(deletedRules.containsAll(rules))
+ {
+ //it is safe to delete this index as it is not shared.
+ for(String indexID : ids)
+ {
+ Index extensibleIndex = extensibleIndexes.getIndex(indexID);
+ entryContainer.deleteDatabase(extensibleIndex);
+ extensibleIndex = null;
+ extensibleIndexes.deleteIndex(indexID);
+ extensibleIndexes.deleteRule(indexID);
+ }
+ }
+ else
+ {
+ for(String indexID : ids)
+ {
+ extensibleIndexes.deleteRule(rule, indexID);
+ }
+ }
+ }
+ }
+ catch(DatabaseException de)
+ {
+ messages.add(
+ Message.raw(StaticUtils.stackTraceToSingleLineString(de)));
+ ccr = new ConfigChangeResult(
+ DirectoryServer.getServerErrorResultCode(), false, messages);
+ return ccr;
+ }
+ finally
+ {
+ entryContainer.exclusiveLock.unlock();
+ }
+ }
+ }
+ else
+ {
+ if(extensibleIndexes != null)
+ {
+ entryContainer.exclusiveLock.lock();
+ try
+ {
+ for(Index extensibleIndex:extensibleIndexes.getIndexes())
+ {
+ entryContainer.deleteDatabase(extensibleIndex);
+ extensibleIndex = null;
+ }
+ extensibleIndexes.deleteAll();
+ }
+ catch(DatabaseException de)
+ {
+ messages.add(
+ Message.raw(StaticUtils.stackTraceToSingleLineString(de)));
+ ccr = new ConfigChangeResult(
+ DirectoryServer.getServerErrorResultCode(), false, messages);
+ return ccr;
+ }
+ finally
+ {
+ entryContainer.exclusiveLock.unlock();
+ }
+ }
+ }
+
indexConfig = cfg;
return new ConfigChangeResult(ResultCode.SUCCESS, adminActionRequired,
@@ -1770,6 +2105,14 @@
{
approximateIndex.setTrusted(txn, trusted);
}
+
+ if(extensibleIndexes!=null)
+ {
+ for(Index extensibleIndex:extensibleIndexes.getIndexes())
+ {
+ extensibleIndex.setTrusted(txn, trusted);
+ }
+ }
}
/**
@@ -1798,11 +2141,22 @@
return false;
}
- if (approximateIndex != null && approximateIndex.isTrusted())
+ if (approximateIndex != null && !approximateIndex.isTrusted())
{
return false;
}
+ if(extensibleIndexes!=null)
+ {
+ for(Index extensibleIndex:extensibleIndexes.getIndexes())
+ {
+ if(extensibleIndex !=null && !extensibleIndex.isTrusted())
+ {
+ return false;
+ }
+ }
+ }
+
return true;
}
@@ -1837,6 +2191,14 @@
{
approximateIndex.setRebuildStatus(rebuildRunning);
}
+
+ if(extensibleIndexes!=null)
+ {
+ for(Index extensibleIndex:extensibleIndexes.getIndexes())
+ {
+ extensibleIndex.setRebuildStatus(rebuildRunning);
+ }
+ }
}
/**
@@ -1900,6 +2262,21 @@
}
/**
+ * Return the mapping of extensible index types and indexes.
+ *
+ * @return The Map of extensible index types and indexes.
+ */
+ public Map<String,Collection<Index>> getExtensibleIndexes()
+ {
+ if(extensibleIndexes == null)
+ {
+ return Collections.emptyMap();
+ }
+ return extensibleIndexes.getIndexMap();
+ }
+
+
+ /**
* Retrieves all the indexes used by this attribute index.
*
* @return A collection of all indexes in use by this attribute
@@ -1933,6 +2310,332 @@
indexes.add(approximateIndex);
}
+ if(extensibleIndexes!=null)
+ {
+ for(Index extensibleIndex:extensibleIndexes.getIndexes())
+ {
+ indexes.add(extensibleIndex);
+ }
+ }
return indexes;
}
-}
+
+
+ /**
+ * Retrieve the entry IDs that might match an extensible filter.
+ *
+ * @param extensibleFilter The extensible filter.
+ * @param debugBuffer If not null, a diagnostic string will be written
+ * which will help determine how the indexes contributed
+ * to this search.
+ * @return The candidate entry IDs that might contain the filter
+ * assertion value.
+ */
+ public EntryIDSet evaluateExtensibleFilter(SearchFilter extensibleFilter,
+ StringBuilder debugBuffer)
+ {
+ //Get the Matching Rule OID of the filter.
+ String nOID = extensibleFilter.getMatchingRuleID();
+ ExtensibleMatchingRule rule =
+ DirectoryServer.getExtensibleMatchingRule(nOID);
+ IndexQueryFactory<IndexQuery> factory = null;
+ if(extensibleIndexes == null
+ || (factory = extensibleIndexes.getQueryFactory(rule))==null)
+ {
+ // There is no index on this matching rule.
+ return IndexQuery.createNullIndexQuery().evaluate();
+ }
+
+ try
+ {
+
+ if(debugBuffer != null)
+ {
+ debugBuffer.append("[INDEX:");
+ IndexConfig config =
+ new JEIndexConfig(indexConfig.getSubstringLength());
+ for(ExtensibleIndexer indexer : rule.getIndexers(config))
+ {
+ String indexerID = indexer.getExtensibleIndexID();
+ String indexName = indexer.getPreferredIndexName();
+ String indexID = " "
+ + extensibleFilter.getAttributeType().getNameOrOID()
+ + "." + indexName
+ + "." +indexerID;
+ debugBuffer.append(indexID);
+ }
+ debugBuffer.append("]");
+ }
+ ByteString assertionValue =
+ extensibleFilter.getAssertionValue().getValue();
+ IndexQuery expression = rule.createIndexQuery(assertionValue, factory);
+ return expression.evaluate();
+ }
+ catch (DirectoryException e)
+ {
+ if (debugEnabled())
+ {
+ TRACER.debugCaught(DebugLogLevel.ERROR, e);
+ }
+ return IndexQuery.createNullIndexQuery().evaluate();
+ }
+ }
+
+ /**
+ * This class manages all the configured extensible matching rules and
+ * their corresponding indexes.
+ */
+ private class ExtensibleMatchingRuleIndex
+ {
+ /**
+ * The mapping of index ID and Index database.
+ */
+ private final Map<String,Index> id2IndexMap;
+
+ /**
+ * The mapping of Index ID and Set the matching rules.
+ */
+ private final Map<String,Set<ExtensibleMatchingRule>> id2RulesMap;
+
+ /**
+ * The Map of configured ExtensibleMatchingRule and the corresponding
+ * IndexQueryFactory.
+ */
+ private final Map<ExtensibleMatchingRule,
+ IndexQueryFactory<IndexQuery>> rule2FactoryMap;
+
+ /**
+ * Creates a new instance of ExtensibleMatchingRuleIndex.
+ */
+ private ExtensibleMatchingRuleIndex()
+ {
+ id2IndexMap = new HashMap<String,Index>();
+ id2RulesMap = new HashMap<String,Set<ExtensibleMatchingRule>>();
+ rule2FactoryMap = new HashMap<ExtensibleMatchingRule,
+ IndexQueryFactory<IndexQuery>>();
+ }
+
+ /**
+ * Returns all configured ExtensibleMatchingRule instances.
+ * @return A Set of extensible matching rules.
+ */
+ private Set<ExtensibleMatchingRule> getRules()
+ {
+ return rule2FactoryMap.keySet();
+ }
+
+ /**
+ * Returns ExtensibleMatchingRule instances for an index.
+ * @param indexID The index ID of an extensible matching rule index.
+ * @return A Set of extensible matching rules corresponding to
+ * an index ID.
+ */
+ private Set<ExtensibleMatchingRule>
+ getRules(String indexID)
+ {
+ Set<ExtensibleMatchingRule> rules = id2RulesMap.get(indexID);
+ if(rules == null)
+ {
+ return Collections.emptySet();
+ }
+ else
+ {
+ return Collections.unmodifiableSet(id2RulesMap.get(indexID));
+ }
+ }
+
+ /**
+ * Returns whether an index is present or not.
+ * @param indexID The index ID of an extensible matching rule index.
+ * @return True if an index is present. False if there is no matching index.
+ */
+ private boolean isIndexPresent(String indexID)
+ {
+ return id2IndexMap.containsKey(indexID);
+ }
+
+
+ /**
+ * Returns the index corresponding to an index ID.
+ * @param indexID The ID of an index.
+ * @return The extensible rule index corresponding to the index ID.
+ */
+ private Index getIndex(String indexID)
+ {
+ return id2IndexMap.get(indexID);
+ }
+
+
+ /**
+ * Adds a new matching Rule and the name of the associated index.
+ * @indexName Name of the index.
+ * @rule An ExtensibleMatchingRule instance that needs to be indexed.
+ */
+ private void addRule(String indexName,ExtensibleMatchingRule rule)
+ {
+ Set<ExtensibleMatchingRule> rules = id2RulesMap.get(indexName);
+ if(rules == null)
+ {
+ rules = new HashSet<ExtensibleMatchingRule>();
+ id2RulesMap.put(indexName, rules);
+ }
+ rules.add(rule);
+ }
+
+ /**
+ * Adds a new Index and its name.
+ * @param index The extensible matching rule index.
+ * @indexName The name of the index.
+ */
+ private void addIndex(Index index,String indexName)
+ {
+ id2IndexMap.put(indexName, index);
+ }
+
+ /**
+ * Returns all the configured extensible indexes.
+ * @return All the available extensible matching rule indexes.
+ */
+ private Collection<Index> getIndexes()
+ {
+ return Collections.unmodifiableCollection(id2IndexMap.values());
+ }
+
+
+ /**
+ * Returns a map of all the configured extensible indexes and their types.
+ * @return A map of all the available extensible matching rule indexes
+ * and their types.
+ */
+ private Map<String,Collection<Index>> getIndexMap()
+ {
+ if(id2IndexMap.isEmpty())
+ {
+ return Collections.emptyMap();
+ }
+ Collection<Index> substring = new ArrayList<Index>();
+ Collection<Index> shared = new ArrayList<Index>();
+ for(Map.Entry<String,Index> entry : id2IndexMap.entrySet())
+ {
+ String indexID = entry.getKey();
+ if(indexID.endsWith(EXTENSIBLE_INDEXER_ID_SUBSTRING))
+ {
+ substring.add(entry.getValue());
+ }
+ else
+ {
+ shared.add(entry.getValue());
+ }
+ }
+ 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);
+ }
+
+
+ /**
+ * Deletes an index corresponding to the index ID.
+ * @param indexID Name of the index.
+ */
+ private void deleteIndex(String indexID)
+ {
+ id2IndexMap.remove(indexID);
+ }
+
+
+ /**
+ * Deletes an extensible matching rule from the list of available rules.
+ * @param rule The ExtensibleMatchingRule that needs to be removed.
+ * @param indexID The name of the index corresponding to the rule.
+ */
+ private void deleteRule(ExtensibleMatchingRule rule,String indexID)
+ {
+ Set<ExtensibleMatchingRule> rules = id2RulesMap.get(indexID);
+ rules.remove(rule);
+ if(rules.size() == 0)
+ {
+ id2RulesMap.remove(indexID);
+ }
+ rule2FactoryMap.remove(rule);
+ }
+
+
+ /**
+ * Adds an ExtensibleMatchingRule and its corresponding IndexQueryFactory.
+ * @param rule An ExtensibleMatchingRule that needs to be added.
+ * @param query A query factory matching the rule.
+ */
+ private void addQueryFactory(ExtensibleMatchingRule rule,
+ IndexQueryFactory<IndexQuery> query)
+ {
+ rule2FactoryMap.put(rule, query);
+ }
+
+
+ /**
+ * Returns the query factory associated with the rule.
+ * @param rule An ExtensibleMatchingRule that needs to be searched.
+ * @return An IndexQueryFactory corresponding to the matching rule.
+ */
+ private IndexQueryFactory<IndexQuery> getQueryFactory(
+ ExtensibleMatchingRule rule)
+ {
+ return rule2FactoryMap.get(rule);
+ }
+
+
+ /**
+ * Deletes extensible matching rules from the list of available rules.
+ * @param indexID The name of the index corresponding to the rules.
+ */
+ private void deleteRule(String indexID)
+ {
+ Set<ExtensibleMatchingRule> rules = id2RulesMap.get(indexID);
+ rule2FactoryMap.remove(rules);
+ rules.clear();
+ id2RulesMap.remove(indexID);
+ }
+
+
+ /**
+ * Deletes all references to matching rules and the indexes.
+ */
+ private void deleteAll()
+ {
+ id2IndexMap.clear();
+ id2RulesMap.clear();
+ rule2FactoryMap.clear();
+ }
+ }
+
+ /**
+ * This class extends the IndexConfig for JE Backend.
+ */
+ private class JEIndexConfig extends IndexConfig
+ {
+ //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)
+ {
+ this.substringLength = substringLength;
+ }
+
+
+ /**
+ * Returns the length of the substring.
+ * @return the length of the substring.
+ */
+ public int getSubstringLength()
+ {
+ return substringLength;
+ }
+ }
+}
\ No newline at end of file
diff --git a/opendj-sdk/opends/src/server/org/opends/server/backends/jeb/BackendImpl.java b/opendj-sdk/opends/src/server/org/opends/server/backends/jeb/BackendImpl.java
index 759789d..ed68cc0 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/backends/jeb/BackendImpl.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/backends/jeb/BackendImpl.java
@@ -22,7 +22,7 @@
* CDDL HEADER END
*
*
- * Copyright 2007-2008 Sun Microsystems, Inc.
+ * Copyright 2007-2009 Sun Microsystems, Inc.
*/
package org.opends.server.backends.jeb;
import org.opends.messages.Message;
@@ -69,9 +69,10 @@
import org.opends.server.admin.std.server.LocalDBIndexCfg;
import org.opends.server.admin.Configuration;
import org.opends.server.admin.server.ConfigurationChangeListener;
+import org.opends.server.api.ExtensibleIndexer;
import org.opends.server.types.DN;
import org.opends.server.backends.jeb.importLDIF.Importer;
-
+import org.opends.server.api.ExtensibleMatchingRule;
/**
* This is an implementation of a Directory Server Backend which stores entries
* locally in a Berkeley DB JE database.
@@ -1131,13 +1132,30 @@
envConfig.setConfigParam("je.env.runCheckpointer", "false");
//Loop through local indexes and see if any are substring.
boolean hasSubIndex = false;
+subIndex:
for (String idx : cfg.listLocalDBIndexes()) {
- LocalDBIndexCfg indexCfg = cfg.getLocalDBIndex(idx);
+ final LocalDBIndexCfg indexCfg = cfg.getLocalDBIndex(idx);
Set<org.opends.server.admin.std.meta.LocalDBIndexCfgDefn.IndexType>
indexType = indexCfg.getIndexType();
if(indexType.contains(org.opends.server.admin.std.
meta.LocalDBIndexCfgDefn.IndexType.SUBSTRING)) {
hasSubIndex = true;
+ break;
+ }
+ Set<ExtensibleMatchingRule> matchingRules =
+ indexCfg.getIndexExtensibleMatchingRule();
+ for(ExtensibleMatchingRule rule: matchingRules)
+ {
+ for(ExtensibleIndexer indexer: rule.getIndexers(null))
+ {
+ String indexID = indexer.getExtensibleIndexID();
+ if(indexID.equals(EXTENSIBLE_INDEXER_ID_SUBSTRING))
+ {
+ //The ExtensibelMatchingRule is of substring type.
+ hasSubIndex = true;
+ break subIndex;
+ }
+ }
}
}
Importer importer = new Importer(importConfig, hasSubIndex);
diff --git a/opendj-sdk/opends/src/server/org/opends/server/backends/jeb/IndexFilter.java b/opendj-sdk/opends/src/server/org/opends/server/backends/jeb/IndexFilter.java
index 14e7eb9..fd46847 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/backends/jeb/IndexFilter.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/backends/jeb/IndexFilter.java
@@ -22,7 +22,7 @@
* CDDL HEADER END
*
*
- * Copyright 2006-2008 Sun Microsystems, Inc.
+ * Copyright 2006-2009 Sun Microsystems, Inc.
*/
package org.opends.server.backends.jeb;
@@ -180,8 +180,15 @@
candidates = evaluateApproximateFilter(filter);
break;
- case NOT:
case EXTENSIBLE_MATCH:
+ if (buffer!= null)
+ {
+ filter.toString(buffer);
+ }
+ candidates = evaluateExtensibleFilter(filter);
+ break;
+
+ case NOT:
default:
if (buffer != null)
{
@@ -537,4 +544,26 @@
return candidates;
}
+ /**
+ * Evaluate an extensible filter against the indexes.
+ *
+ * @param extensibleFilter The extensible filter to be evaluated.
+ * @return A set of entry IDs representing candidate entries.
+ */
+ private EntryIDSet evaluateExtensibleFilter(SearchFilter extensibleFilter)
+ {
+ EntryIDSet candidates;
+ AttributeIndex attributeIndex =
+ entryContainer.getAttributeIndex(extensibleFilter.getAttributeType());
+ if (attributeIndex == null)
+ {
+ candidates = IndexQuery.createNullIndexQuery().evaluate();
+ }
+ else
+ {
+ candidates =
+ attributeIndex.evaluateExtensibleFilter(extensibleFilter, buffer);
+ }
+ return candidates;
+ }
}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/backends/jeb/IndexQuery.java b/opendj-sdk/opends/src/server/org/opends/server/backends/jeb/IndexQuery.java
new file mode 100644
index 0000000..23e3e82
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/backends/jeb/IndexQuery.java
@@ -0,0 +1,209 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ * Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ * Copyright 2009 Sun Microsystems, Inc.
+ */
+
+
+package org.opends.server.backends.jeb;
+
+import java.util.Collection;
+import static org.opends.server.backends.jeb.IndexFilter.*;
+
+
+/**
+ * This class represents a JE Backend Query.
+ */
+@org.opends.server.types.PublicAPI(
+ stability=org.opends.server.types.StabilityLevel.VOLATILE,
+ mayInstantiate=false,
+ mayExtend=true,
+ mayInvoke=false)
+public abstract class IndexQuery
+{
+ /**
+ * Evaluates the index query and returns the EntryIDSet.
+ * @return The EntryIDSet as a result of evaulation of this query.
+ */
+ public abstract EntryIDSet evaluate();
+
+
+
+ /**
+ * Creates an IntersectionIndexQuery object from a collection of IndexQuery
+ * objects.
+ * @param subIndexQueries A collection of IndexQuery objects.
+ * @return An IntersectionIndexQuery object.
+ */
+ public static IndexQuery createIntersectionIndexQuery(
+ Collection<IndexQuery> subIndexQueries)
+ {
+ return new IntersectionIndexQuery(subIndexQueries);
+ }
+
+
+
+ /**
+ * Creates a union IndexQuery object from a collection of IndexQuery
+ * objects.
+ * @param subIndexQueries Collection of IndexQuery objects.
+ * @return A UnionIndexQuery object.
+ */
+ public static IndexQuery createUnionIndexQuery(
+ Collection<IndexQuery> subIndexQueries)
+ {
+ return new UnionIndexQuery(subIndexQueries);
+ }
+
+
+
+ /**
+ * Creates an empty IndexQuery object.
+ * @return A NullIndexQuery object.
+ */
+ public static IndexQuery createNullIndexQuery()
+ {
+ return new NullIndexQuery();
+ }
+}
+
+
+
+/**
+* This class creates a Null IndexQuery. It is used when there
+* is no record in the index. It may also be used when the
+ * index contains all the records but an empty EntryIDSet should be
+ * returned as part of the optimization.
+*/
+final class NullIndexQuery extends IndexQuery
+{
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EntryIDSet evaluate()
+ {
+ return new EntryIDSet();
+ }
+}
+
+
+
+
+
+/**
+ * This class creates an intersection IndexQuery from a collection of
+ * IndexQuery objects.
+ */
+final class IntersectionIndexQuery extends IndexQuery
+{
+ /**
+ * Collection of IndexQuery objects.
+ */
+ private final Collection<IndexQuery> subIndexQueries;
+
+
+ /**
+ * Creates an instance of IntersectionIndexQuery.
+ * @param subIndexQueries Collection of IndexQuery objects.
+ */
+ IntersectionIndexQuery(Collection<IndexQuery> subIndexQueries)
+ {
+ this.subIndexQueries = subIndexQueries;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EntryIDSet evaluate()
+ {
+ EntryIDSet entryIDs = null;
+ for (IndexQuery query : subIndexQueries)
+ {
+ if (entryIDs == null)
+ {
+ entryIDs = query.evaluate();
+ }
+ else
+ {
+ entryIDs.retainAll(query.evaluate());
+ }
+ if (entryIDs.isDefined() &&
+ entryIDs.size() <= FILTER_CANDIDATE_THRESHOLD)
+ {
+ break;
+ }
+ }
+ return entryIDs;
+ }
+}
+
+/**
+ * This class creates a union of IndexQuery objects.
+ */
+final class UnionIndexQuery extends IndexQuery
+{
+ /**
+ * Collection containing IndexQuery objects.
+ */
+ private final Collection<IndexQuery> subIndexQueries;
+
+ /**
+ * Creates an instance of UnionIndexQuery.
+ * @param subIndexQueries The Collection of IndexQuery objects.
+ */
+ UnionIndexQuery(Collection<IndexQuery> subIndexQueries)
+ {
+ this.subIndexQueries = subIndexQueries;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EntryIDSet evaluate()
+ {
+ EntryIDSet entryIDs = null;
+ for (IndexQuery query : subIndexQueries)
+ {
+ if (entryIDs == null)
+ {
+ entryIDs = query.evaluate();
+ }
+ else
+ {
+ entryIDs.addAll(query.evaluate());
+ }
+ if (entryIDs.isDefined() &&
+ entryIDs.size() <= FILTER_CANDIDATE_THRESHOLD)
+ {
+ break;
+ }
+ }
+ return entryIDs;
+ }
+}
\ No newline at end of file
diff --git a/opendj-sdk/opends/src/server/org/opends/server/backends/jeb/IndexQueryFactoryImpl.java b/opendj-sdk/opends/src/server/org/opends/server/backends/jeb/IndexQueryFactoryImpl.java
new file mode 100644
index 0000000..55efb41
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/backends/jeb/IndexQueryFactoryImpl.java
@@ -0,0 +1,152 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ * Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ * Copyright 2009 Sun Microsystems, Inc.
+ */
+
+
+package org.opends.server.backends.jeb;
+
+import com.sleepycat.je.DatabaseEntry;
+import com.sleepycat.je.LockMode;
+import java.util.Collection;
+import java.util.Map;
+import org.opends.server.api.IndexQueryFactory;
+
+/**
+ * This class is an implementation of IndexQueryFactory which creates
+ * IndexQuery objects as part of the query of the JEB index.
+*/
+public final class IndexQueryFactoryImpl
+ implements IndexQueryFactory<IndexQuery>
+{
+ /**
+ * The Map containing the string type identifier and the corresponding index.
+ */
+ private Map<String,Index> indexMap;
+
+
+
+ /**
+ * Creates a new IndexQueryFactoryImpl object.
+ * @param indexMap A map containing the index id and the corresponding index.
+ */
+ public IndexQueryFactoryImpl(Map<String,Index> indexMap)
+ {
+ this.indexMap = indexMap;
+ }
+
+
+
+ /**
+ *{@inheritDoc}
+ */
+ public IndexQuery createExactMatchQuery(final String indexID,
+ final byte[] value)
+ {
+ return new IndexQuery()
+ {
+
+ @Override
+ public EntryIDSet evaluate()
+ {
+ //Read the database and get Record for the key.
+ DatabaseEntry key = new DatabaseEntry(value);
+ //Select the right index to be used.
+ Index index = indexMap.get(indexID);
+ EntryIDSet entrySet = index.readKey(key,null,LockMode.DEFAULT);
+ return entrySet;
+ }
+ };
+ }
+
+
+
+ /**
+ *{@inheritDoc}
+ */
+ public IndexQuery createRangeMatchQuery(
+ final String indexID,
+ final byte[] lowerBound,
+ final byte[] upperBound,
+ final boolean includeLowerBound,
+ final boolean includeUpperBound)
+ {
+ return new IndexQuery()
+ {
+
+ @Override
+ public EntryIDSet evaluate()
+ {
+ //Find the right index.
+ Index index = indexMap.get(indexID);
+ EntryIDSet entrySet = index.readRange(lowerBound,upperBound,
+ includeLowerBound,
+ includeUpperBound);
+ return entrySet;
+ }
+ };
+ }
+
+
+
+ /**
+ *{@inheritDoc}
+ */
+ public IndexQuery createIntersectionQuery(Collection<IndexQuery>
+ subqueries)
+ {
+ return IndexQuery.createIntersectionIndexQuery(subqueries);
+ }
+
+
+
+ /**
+ *{@inheritDoc}
+ */
+ public IndexQuery createUnionQuery(Collection<IndexQuery> subqueries)
+ {
+ return IndexQuery.createUnionIndexQuery(subqueries);
+ }
+
+
+
+ /**
+ *{@inheritDoc}
+ * It returns an empty EntryIDSet object when either all or no record sets
+ * are requested.
+ */
+ public IndexQuery createMatchAllQuery()
+ {
+ return new IndexQuery()
+ {
+
+ @Override
+ public EntryIDSet evaluate()
+ {
+ return new EntryIDSet();
+ }
+ };
+ }
+}
\ No newline at end of file
diff --git a/opendj-sdk/opends/src/server/org/opends/server/backends/jeb/JEExtensibleIndexer.java b/opendj-sdk/opends/src/server/org/opends/server/backends/jeb/JEExtensibleIndexer.java
new file mode 100644
index 0000000..6e2e9d7
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/backends/jeb/JEExtensibleIndexer.java
@@ -0,0 +1,221 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ * Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ * Copyright 2009 Sun Microsystems, Inc.
+ */
+
+
+package org.opends.server.backends.jeb;
+
+import org.opends.server.api.ExtensibleIndexer;
+import org.opends.server.types.AttributeType;
+import org.opends.server.types.AttributeValue;
+import org.opends.server.types.Entry;
+import org.opends.server.types.Modification;
+import org.opends.server.api.ExtensibleMatchingRule;
+import org.opends.server.types.Attribute;
+
+
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+
+/**
+ *This class implements an Indexer for extensible matching rules in JE Backend.
+ */
+public final class JEExtensibleIndexer extends Indexer
+{
+ /**
+ * The comparator for index keys generated by this class.
+ */
+ private static final Comparator<byte[]> comparator =
+ new AttributeIndex.KeyComparator();
+
+
+
+ /**
+ * The attribute type for which this instance will
+ * generate index keys.
+ */
+ private final AttributeType attributeType;
+
+
+
+ /**
+ * The extensible indexer which will generate the keys
+ * for the associated extensible matching rule.
+ */
+ private final ExtensibleIndexer extensibleIndexer;
+
+
+
+ /**
+ * The extensible matching rule which needs to be indexed.
+ */
+ private final ExtensibleMatchingRule matchingRule;
+
+
+
+ /**
+ * Creates a new extensible indexer for JE backend.
+ *
+ * @param attributeType The attribute type for which an indexer is
+ * required.
+ * @param matchingRule The extensible matching rule to be indexed.
+ * @param extensibleIndexer The extensible indexer to be used.
+ */
+ public JEExtensibleIndexer(AttributeType attributeType,
+ ExtensibleMatchingRule matchingRule,
+ ExtensibleIndexer extensibleIndexer)
+ {
+ this.attributeType = attributeType;
+ this.matchingRule = matchingRule;
+ this.extensibleIndexer = extensibleIndexer;
+ }
+
+
+
+ /**
+ * Gets a string representation of this object. The returned value is
+ * used to name an index created using this object.
+ * @return A string representation of this object.
+ */
+ @Override
+ public String toString()
+ {
+ return attributeType.getNameOrOID() + "."
+ + extensibleIndexer.getExtensibleIndexID();
+ }
+
+
+
+ /**
+ * Gets the comparator that must be used to compare index keys
+ * generated by this class.
+ *
+ * @return A byte array comparator.
+ */
+ public Comparator<byte[]> getComparator()
+ {
+ return comparator;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void indexEntry(Entry entry, Set<byte[]> keys)
+ {
+ List<Attribute> attrList =
+ entry.getAttribute(attributeType);
+ if (attrList != null)
+ {
+ indexAttribute(attrList, keys);
+ }
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void replaceEntry(Entry oldEntry, Entry newEntry,
+ Map<byte[], Boolean> modifiedKeys)
+ {
+ List<Attribute> newAttributes = newEntry.getAttribute(attributeType, true);
+ List<Attribute> oldAttributes = oldEntry.getAttribute(attributeType, true);
+
+ indexAttribute(oldAttributes, modifiedKeys, false);
+ indexAttribute(newAttributes, modifiedKeys, true);
+ }
+
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void modifyEntry(Entry oldEntry, Entry newEntry,
+ List<Modification> mods,
+ Map<byte[], Boolean> modifiedKeys)
+ {
+ List<Attribute> newAttributes = newEntry.getAttribute(attributeType, true);
+ List<Attribute> oldAttributes = oldEntry.getAttribute(attributeType, true);
+
+ indexAttribute(oldAttributes, modifiedKeys, false);
+ indexAttribute(newAttributes, modifiedKeys, true);
+ }
+
+
+
+ /**
+ * Generates the set of extensible index keys for an attribute.
+ * @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<byte[]> keys)
+ {
+ if (attrList == null) return;
+
+ for (Attribute attr : attrList)
+ {
+ for (AttributeValue value : attr)
+ {
+ extensibleIndexer.getKeys(value, keys);
+ }
+ }
+ }
+
+
+
+ /**
+ * Generates the set of index keys for an attribute.
+ * @param attrList The attribute to be indexed.
+ * @param modifiedKeys The map into which the modified
+ * keys will be inserted.
+ * @param insert <code>true</code> if generated keys should
+ * be inserted or <code>false</code> otherwise.
+ */
+ private void indexAttribute(List<Attribute> attrList,
+ Map<byte[], Boolean> modifiedKeys,
+ Boolean insert)
+ {
+ if (attrList == null) return;
+
+ for (Attribute attr : attrList)
+ {
+ for (AttributeValue value : attr)
+ {
+ extensibleIndexer.getKeys(value,modifiedKeys,insert);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/opendj-sdk/opends/src/server/org/opends/server/backends/jeb/importLDIF/WorkThread.java b/opendj-sdk/opends/src/server/org/opends/server/backends/jeb/importLDIF/WorkThread.java
index 8b8f16e..651134e 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/backends/jeb/importLDIF/WorkThread.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/backends/jeb/importLDIF/WorkThread.java
@@ -22,12 +22,13 @@
* CDDL HEADER END
*
*
- * Copyright 2008 Sun Microsystems, Inc.
+ * Copyright 2008-2009 Sun Microsystems, Inc.
*/
package org.opends.server.backends.jeb.importLDIF;
import static org.opends.server.loggers.debug.DebugLogger.*;
+import static org.opends.server.util.ServerConstants.*;
import org.opends.server.loggers.debug.DebugTracer;
import org.opends.server.types.*;
import org.opends.server.api.DirectoryThread;
@@ -37,7 +38,6 @@
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.*;
-import org.opends.server.util.*;
import com.sleepycat.je.*;
@@ -127,6 +127,7 @@
* to flush and exit.
*
*/
+ @Override
public void run()
{
try {
@@ -222,6 +223,12 @@
if((index=attributeIndex.getApproximateIndex()) != null) {
delete(index, existingEntry, entryID);
}
+ for(Collection<Index> indexes :
+ attributeIndex.getExtensibleIndexes().values()) {
+ for(Index extensibleIndex: indexes) {
+ delete(extensibleIndex,existingEntry,entryID);
+ }
+ }
}
for(VLVIndex vlvIdx : context.getEntryContainer().getVLVIndexes()) {
vlvIdx.removeEntry(txn, entryID, existingEntry);
@@ -276,6 +283,26 @@
for(VLVIndex vlvIdx : context.getEntryContainer().getVLVIndexes()) {
vlvIdx.addEntry(txn, entryID, entry);
}
+ Map<String,Collection<Index>> extensibleMap =
+ attributeIndex.getExtensibleIndexes();
+ if(!extensibleMap.isEmpty()) {
+ Collection<Index> subIndexes =
+ attributeIndex.getExtensibleIndexes().get(
+ EXTENSIBLE_INDEXER_ID_SUBSTRING);
+ if(subIndexes != null) {
+ for(Index subIndex: subIndexes) {
+ bufferMgr.insert(subIndex, entry, entryID, insertKeySet);
+ }
+ }
+ Collection<Index> sharedIndexes =
+ attributeIndex.getExtensibleIndexes().get(
+ EXTENSIBLE_INDEXER_ID_SHARED);
+ if(sharedIndexes !=null) {
+ for(Index sharedIndex:sharedIndexes) {
+ insert(sharedIndex,entry,entryID);
+ }
+ }
+ }
}
}
}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/core/DirectoryServer.java b/opendj-sdk/opends/src/server/org/opends/server/core/DirectoryServer.java
index bd3e97a..9551fdc 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/core/DirectoryServer.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/core/DirectoryServer.java
@@ -22,7 +22,7 @@
* CDDL HEADER END
*
*
- * Copyright 2006-2008 Sun Microsystems, Inc.
+ * Copyright 2006-2009 Sun Microsystems, Inc.
*/
package org.opends.server.core;
@@ -75,6 +75,7 @@
import org.opends.server.api.AccessControlHandler;
import org.opends.server.api.plugin.PluginType;
import org.opends.server.api.plugin.PluginResult;
+import org.opends.server.api.ExtensibleMatchingRule;
import org.opends.server.backends.RootDSEBackend;
import static org.opends.server.config.ConfigConstants.DN_CONFIG_ROOT;
import static org.opends.server.config.ConfigConstants.DN_MONITOR_ROOT;
@@ -3515,6 +3516,41 @@
/**
+ * Retrieves the set of extensible matching rules registered with the
+ * Directory Server. The mapping will be between the lowercase name or OID
+ * for each extensible matching rule and the matching rule implementation. The
+ * same extensible matching rule instance may be included multiple times with
+ * different keys.
+ *
+ * @return The set of extensible matching rules registered with the Directory
+ * Server.
+ */
+ public static Map<String,ExtensibleMatchingRule>
+ getExtensibleMatchingRules()
+ {
+ return directoryServer.schema.getExtensibleMatchingRules();
+ }
+
+
+
+ /**
+ * Retrieves the extensible matching rule with the specified name or OID.
+ *
+ * @param lowerName The lowercase name or OID for the extensible matching
+ * rule to retrieve.
+ *
+ * @return The requested extensible matching rule, or <CODE>null</CODE> if no
+ * such matching rule has been defined in the server.
+ */
+ public static ExtensibleMatchingRule
+ getExtensibleMatchingRule(String lowerName)
+ {
+ return directoryServer.schema.getExtensibleMatchingRule(lowerName);
+ }
+
+
+
+ /**
* Retrieves the set of objectclasses defined in the Directory Server.
*
* @return The set of objectclasses defined in the Directory Server.
diff --git a/opendj-sdk/opends/src/server/org/opends/server/schema/CollationMatchingRuleFactory.java b/opendj-sdk/opends/src/server/org/opends/server/schema/CollationMatchingRuleFactory.java
index 8868702..0237d4a 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/schema/CollationMatchingRuleFactory.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/schema/CollationMatchingRuleFactory.java
@@ -22,7 +22,7 @@
* CDDL HEADER END
*
*
- * Copyright 2008 Sun Microsystems, Inc.
+ * Copyright 2008-2009 Sun Microsystems, Inc.
*/
@@ -44,21 +44,27 @@
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
+import java.util.TreeSet;
import org.opends.messages.Message;
import org.opends.server.admin.server.ConfigurationChangeListener;
import org.opends.server.admin.std.meta.CollationMatchingRuleCfgDefn.
MatchingRuleType;
+import org.opends.server.api.ExtensibleIndexer;
+import org.opends.server.api.IndexQueryFactory;
import org.opends.server.api.MatchingRuleFactory;
import org.opends.server.admin.std.server.CollationMatchingRuleCfg;
import org.opends.server.api.ExtensibleMatchingRule;
import org.opends.server.api.MatchingRule;
+import org.opends.server.backends.jeb.AttributeIndex;
import org.opends.server.config.ConfigException;
import org.opends.server.core.DirectoryServer;
import org.opends.server.protocols.asn1.ASN1OctetString;
+import org.opends.server.types.AttributeValue;
import org.opends.server.types.ByteString;
import org.opends.server.types.ConditionResult;
import org.opends.server.types.ConfigChangeResult;
import org.opends.server.types.DirectoryException;
+import org.opends.server.types.IndexConfig;
import org.opends.server.types.InitializationException;
import org.opends.server.types.ResultCode;
@@ -68,6 +74,8 @@
import static org.opends.messages.CoreMessages.*;
import static org.opends.messages.ConfigMessages.*;
import static org.opends.server.util.StaticUtils.*;
+import static org.opends.server.api.ExtensibleIndexer.*;
+import static org.opends.server.util.ServerConstants.*;
@@ -118,9 +126,9 @@
}
-/**
- * Creates a new instance of CollationMatchingRuleFactory.
- */
+ /**
+ * Creates a new instance of CollationMatchingRuleFactory.
+ */
public CollationMatchingRuleFactory()
{
//Initialize the matchingRules.
@@ -130,8 +138,8 @@
/**
- * {@inheritDoc}
- */
+ * {@inheritDoc}
+ */
@Override
public final Collection<MatchingRule> getMatchingRules()
{
@@ -140,16 +148,16 @@
- /**
- * Adds a new mapping of OID and MatchingRule.
- *
- * @param oid OID of the matching rule
- * @param matchingRule instance of a MatchingRule.
- */
+ /**
+ * Adds a new mapping of OID and MatchingRule.
+ *
+ * @param oid OID of the matching rule
+ * @param matchingRule instance of a MatchingRule.
+ */
private final void addMatchingRule(String oid,
MatchingRule matchingRule)
{
- matchingRules.put(oid, matchingRule);
+ matchingRules.put(oid, matchingRule);
}
@@ -179,10 +187,10 @@
/**
- * Reads the configuration and initializes matching rule types.
- *
- * @param ruleTypes The Set containing allowed matching rule types.
- */
+ * Reads the configuration and initializes matching rule types.
+ *
+ * @param ruleTypes The Set containing allowed matching rule types.
+ */
private void initializeMatchingRuleTypes(SortedSet<MatchingRuleType>
ruleTypes)
{
@@ -209,19 +217,19 @@
substringMatchingRuleType = true;
break;
default:
- //No default values allowed.
+ //No default values allowed.
}
}
}
- /**
- * Creates a new Collator instance.
- *
- * @param locale Locale for the collator
- * @return Returns a new Collator instance
- */
+ /**
+ * Creates a new Collator instance.
+ *
+ * @param locale Locale for the collator
+ * @return Returns a new Collator instance
+ */
private Collator createCollator(Locale locale)
{
Collator collator = Collator.getInstance(locale);
@@ -232,9 +240,9 @@
- /**
- * {@inheritDoc}
- */
+ /**
+ * {@inheritDoc}
+ */
@Override
public void initializeMatchingRule(CollationMatchingRuleCfg configuration)
throws ConfigException, InitializationException
@@ -271,7 +279,7 @@
Message msg =
WARN_ATTR_INVALID_COLLATION_MATCHING_RULE_LOCALE.
get(collation,configuration.dn().toNormalizedString(),
- languageTag);
+ languageTag);
logError(msg);
}
@@ -332,7 +340,6 @@
for(String collation:configuration.getCollation())
{
CollationMapper mapper = new CollationMapper(collation);
- String nOID = mapper.getNumericOID();
String languageTag = mapper.getLanguageTag();
Locale locale = getLocale(languageTag);
createLessThanMatchingRule(mapper,locale);
@@ -352,10 +359,10 @@
}
catch (DirectoryException de)
{
- Message message = WARN_CONFIG_SCHEMA_MR_CONFLICTING_MR.get(
- String.valueOf(configuration.dn()), de.getMessageObject());
- adminActionRequired = true;
- messages.add(message);
+ Message message = WARN_CONFIG_SCHEMA_MR_CONFLICTING_MR.get(
+ String.valueOf(configuration.dn()), de.getMessageObject());
+ adminActionRequired = true;
+ messages.add(message);
}
currentConfig = configuration;
return new ConfigChangeResult(resultCode, adminActionRequired, messages);
@@ -405,7 +412,7 @@
Message msg =
WARN_ATTR_INVALID_COLLATION_MATCHING_RULE_LOCALE.
get(collation,configuration.dn().toNormalizedString(),
- languageTag);
+ languageTag);
unacceptableReasons.add(msg);
configAcceptable = false;
continue;
@@ -417,11 +424,11 @@
/**
- * Creates Less-than Matching Rule.
- *
- * @param mapper CollationMapper containing OID and the language Tag.
- * @param locale Locale value
- */
+ * Creates Less-than Matching Rule.
+ *
+ * @param mapper CollationMapper containing OID and the language Tag.
+ * @param locale Locale value
+ */
private void createLessThanMatchingRule(CollationMapper mapper,Locale locale)
{
if(!lessThanMatchingRuleType)
@@ -449,12 +456,12 @@
- /**
- * Creates Less-Than-Equal-To Matching Rule.
- *
- * @param mapper CollationMapper containing OID and the language Tag.
- * @param locale Locale value
- */
+ /**
+ * Creates Less-Than-Equal-To Matching Rule.
+ *
+ * @param mapper CollationMapper containing OID and the language Tag.
+ * @param locale Locale value
+ */
private void createLessThanOrEqualToMatchingRule(CollationMapper mapper,
Locale locale)
{
@@ -484,12 +491,12 @@
- /**
- * Creates Equality Matching Rule.
- *
- * @param mapper CollationMapper containing OID and the language Tag.
- * @param locale Locale value
- */
+ /**
+ * Creates Equality Matching Rule.
+ *
+ * @param mapper CollationMapper containing OID and the language Tag.
+ * @param locale Locale value
+ */
private void createEqualityMatchingRule(CollationMapper mapper,Locale locale)
{
if(!equalityMatchingRuleType)
@@ -510,37 +517,37 @@
names.add(lTag);
matchingRule =
- new CollationEqualityMatchingRule(nOID,names,locale);
+ new CollationEqualityMatchingRule(nOID,
+ Collections.<String>emptySet(),locale);
addMatchingRule(nOID, matchingRule);
// Register OID.3 as the equality matching rule.
String OID = mapper.getNumericOID() + ".3";
MatchingRule equalityMatchingRule = getMatchingRule(OID);
- Collection<String> equalityNames = new HashSet<String>();
if(equalityMatchingRule!=null)
{
for(String name: equalityMatchingRule.getAllNames())
{
- equalityNames.add(name);
+ names.add(name);
}
}
- equalityNames.add(lTag+".eq");
- equalityNames.add(lTag+".3");
+ names.add(lTag+".eq");
+ names.add(lTag+".3");
equalityMatchingRule =
- new CollationEqualityMatchingRule(OID,equalityNames,locale);
+ new CollationEqualityMatchingRule(OID,names,locale);
addMatchingRule(OID, equalityMatchingRule);
}
/**
- * Creates Greater-than-equal-to Matching Rule.
- *
- * @param mapper CollationMapper containing OID and the language Tag.
- * @param locale Locale value
- */
+ * Creates Greater-than-equal-to Matching Rule.
+ *
+ * @param mapper CollationMapper containing OID and the language Tag.
+ * @param locale Locale value
+ */
private void createGreaterThanOrEqualToMatchingRule(CollationMapper mapper,
Locale locale)
{
@@ -569,12 +576,12 @@
- /**
- * Creates Greater-than Matching Rule.
- *
- * @param mapper CollationMapper containing OID and the language Tag.
- * @param locale Locale value
- */
+ /**
+ * Creates Greater-than Matching Rule.
+ *
+ * @param mapper CollationMapper containing OID and the language Tag.
+ * @param locale Locale value
+ */
private void createGreaterThanMatchingRule(CollationMapper mapper,
Locale locale)
{
@@ -603,12 +610,12 @@
- /**
- * Creates substring Matching Rule.
- *
- * @param mapper CollationMapper containing OID and the language Tag.
- * @param locale Locale value
- */
+ /**
+ * Creates substring Matching Rule.
+ *
+ * @param mapper CollationMapper containing OID and the language Tag.
+ * @param locale Locale value
+ */
private void createSubstringMatchingRule(CollationMapper mapper,Locale locale)
{
if(!substringMatchingRuleType)
@@ -636,12 +643,12 @@
- /**
- * Verifies if the locale is supported by the JVM.
- *
- * @param lTag The language tag specified in the configuration.
- * @return Locale The locale correspoding to the languageTag.
- */
+ /**
+ * Verifies if the locale is supported by the JVM.
+ *
+ * @param lTag The language tag specified in the configuration.
+ * @return Locale The locale correspoding to the languageTag.
+ */
private Locale getLocale(String lTag)
{
//Separates the language and the country from the locale.
@@ -685,35 +692,51 @@
- /**
- *Collation rule for Equality matching rule.
- */
- private final class CollationEqualityMatchingRule
- extends ExtensibleMatchingRule
+ /**
+ * Collation Extensible matching rule.
+ */
+ private abstract class CollationMatchingRule
+ extends ExtensibleMatchingRule
{
//Names for this class.
private final Collection<String> names;
+
+
//Collator for performing equality match.
- private final Collator collator;
+ protected final Collator collator;
+
+
//Numeric OID of the rule.
private final String nOID;
+
+ //Locale associated with this rule.
+ private final Locale locale;
+
+
+
+ //Indexer of this rule.
+ protected ExtensibleIndexer indexer;
+
+
+
/**
- * Constructs a new CollationEqualityMatchingRule.
+ * Constructs a new CollationMatchingRule.
*
* @param nOID OID of the collation matching rule
* @param names names of this matching rule
* @param locale Locale of the collation matching rule
*/
- private CollationEqualityMatchingRule(String nOID,Collection<String> names,
+ private CollationMatchingRule(String nOID,Collection<String> names,
Locale locale)
{
super();
this.names = names;
- this.collator =createCollator(locale);
+ this.collator = createCollator(locale);
+ this.locale = locale;
this.nOID = nOID;
}
@@ -747,6 +770,7 @@
}
+
/**
* {@inheritDoc}
*/
@@ -782,6 +806,74 @@
/**
+ * Returns the name of the index database for this matching rule.
+ * An index name for this rule will be based upon the Locale. This will
+ * ensure that multiple collation matching rules corresponding to the same
+ * Locale can share the same index database.
+ * @return The name of the index for this matching rule.
+ */
+ public String getIndexName()
+ {
+ String language = locale.getLanguage();
+ String country = locale.getCountry();
+ String variant = locale.getVariant();
+ StringBuilder builder = new StringBuilder(language);
+ if (country != null && country.length() > 0)
+ {
+ builder.append("_");
+ builder.append(locale.getCountry());
+ }
+ if (variant != null && variant.length() > 0)
+ {
+ builder.append("_");
+ builder.append(locale.getVariant());
+ }
+ return builder.toString();
+ }
+
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Collection<ExtensibleIndexer> getIndexers(IndexConfig config)
+ {
+ if(indexer == null)
+ {
+ //The default implementation contains shared indexer and doesn't use the
+ //config.
+ indexer = new CollationSharedExtensibleIndexer(this);
+ }
+ return Collections.singletonList(indexer);
+ }
+ }
+
+
+
+ /**
+ *Collation rule for Equality matching rule.
+ */
+ private final class CollationEqualityMatchingRule
+ extends CollationMatchingRule
+ {
+ /**
+ * Constructs a new CollationEqualityMatchingRule.
+ *
+ * @param nOID OID of the collation matching rule
+ * @param names names of this matching rule
+ * @param locale Locale of the collation matching rule
+ */
+ private CollationEqualityMatchingRule(String nOID,Collection<String> names,
+ Locale locale)
+ {
+ super(nOID,names,locale);
+ }
+
+
+
+ /**
* {@inheritDoc}
*/
@Override
@@ -794,18 +886,18 @@
- /**
- * Indicates whether the two provided normalized values are equal to
- * each other.
- *
- * @param value1 The normalized form of the first value to
- * compare.
- * @param value2 The normalized form of the second value to
- * compare.
- *
- * @return {@code true} if the provided values are equal, or
- * {@code false} if not.
- */
+ /**
+ * Indicates whether the two provided normalized values are equal to
+ * each other.
+ *
+ * @param value1 The normalized form of the first value to
+ * compare.
+ * @param value2 The normalized form of the second value to
+ * compare.
+ *
+ * @return {@code true} if the provided values are equal, or
+ * {@code false} if not.
+ */
private boolean areEqual(ByteString value1, ByteString value2)
{
return Arrays.equals(value1.value(), value2.value());
@@ -829,23 +921,35 @@
return ConditionResult.FALSE;
}
}
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public <T> T createIndexQuery(ByteString assertionValue,
+ IndexQueryFactory<T> factory) throws DirectoryException
+ {
+ //Normalize the assertion value.
+ ByteString normalValue = normalizeValue(assertionValue);
+ return factory.createExactMatchQuery(
+ indexer.getExtensibleIndexID(),
+ normalValue.value());
+ }
}
- /**
- * Collation rule for Substring matching rule.
- */
+
+ /**
+ * Collation rule for Substring matching rule.
+ */
private final class CollationSubstringMatchingRule
- extends ExtensibleMatchingRule
+ extends CollationMatchingRule
{
- //Names for this class.
- private final Collection<String> names;
+ //Substring Indexer associated with this instance.
+ private CollationSubstringExtensibleIndexer subIndexer;
- //Collator for performing equality match.
- private final Collator collator;
-
- //Numeric OID of the rule.
- private final String nOID;
/**
@@ -858,10 +962,7 @@
private CollationSubstringMatchingRule(String nOID,
Collection<String> names,Locale locale)
{
- super();
- this.names = names;
- this.collator =createCollator(locale);
- this.nOID = nOID;
+ super(nOID,names,locale);
}
@@ -870,67 +971,6 @@
* {@inheritDoc}
*/
@Override
- public String getName()
- {
- //Concatenate all the names and return.
- StringBuilder builder = new StringBuilder();
- for(String name: getAllNames())
- {
- builder.append(name);
- builder.append("\b");
- }
- return builder.toString();
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- @Override
- public Collection<String> getAllNames()
- {
- return Collections.unmodifiableCollection(names);
- }
-
-
- /**
- * {@inheritDoc}
- */
- @Override
- public String getOID()
- {
- return nOID;
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- @Override
- public String getDescription()
- {
- return null;
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- @Override
- public String getSyntaxOID()
- {
- return SYNTAX_DIRECTORY_STRING_OID;
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- @Override
public ByteString normalizeValue(ByteString value)
throws DirectoryException
{
@@ -940,12 +980,81 @@
- /**
- * {@inheritDoc}
- */
- @Override
- public ByteString normalizeAssertionValue(ByteString value)
- throws DirectoryException
+ /**
+ * Utility class which abstracts a substring assertion value.
+ */
+ private final class Assertion
+ {
+ //Initial part of the substring filter.
+ private String subInitial;
+
+
+ //any parts of the substring filter.
+ private List<String> subAny;
+
+
+ //Final part of the substring filter.
+ private String subFinal;
+
+
+
+ /**
+ * Creates a new instance of Assertion.
+ * @param subInitial Initial part of the filter.
+ * @param subAny Any part of the filter.
+ * @param subFinal Final part of the filter.
+ */
+ Assertion(String subInitial, List<String> subAny, String subFinal)
+ {
+ this.subInitial = subInitial;
+ this.subAny = subAny;
+ this.subFinal = subFinal;
+ }
+
+
+
+ /**
+ * Returns the Initial part of the assertion.
+ * @return Initial part of assertion.
+ */
+ private String getInitial()
+ {
+ return subInitial;
+ }
+
+
+
+ /**
+ * Returns the any part of the assertion.
+ * @return Any part of the assertion.
+ */
+ private List<String> getAny()
+ {
+ return subAny;
+ }
+
+
+
+ /**
+ * Returns the final part of the assertion.
+ * @return Final part of the assertion.
+ */
+ private String getFinal()
+ {
+ return subFinal;
+ }
+ }
+
+
+
+ /**
+ * Parses the assertion from a given value.
+ * @param value The value that needs to be parsed.
+ * @return The parsed Assertion object containing the
+ * @throws org.opends.server.types.DirectoryException
+ */
+ private Assertion parseAssertion(ByteString value)
+ throws DirectoryException
{
// Get a string representation of the value.
String filterString = value.stringValue();
@@ -973,7 +1082,7 @@
if (asteriskPositions.isEmpty())
{
Message message = ERR_SEARCH_FILTER_SUBSTRING_NO_ASTERISKS.get(
- filterString, 0, endPos);
+ filterString, 0, endPos);
throw new DirectoryException(
ResultCode.PROTOCOL_ERROR, message);
}
@@ -1094,7 +1203,19 @@
subFinal = filterString.substring(firstPos+1, length + firstPos + 1);
}
}
+ return new Assertion(subInitial, subAny, subFinal);
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public ByteString normalizeAssertionValue(ByteString value)
+ throws DirectoryException {
+ Assertion assertion = parseAssertion(value);
+ String subInitial = assertion.getInitial();
// Normalize the Values in the following format:
// initialLength, initial, numberofany, anyLength1, any1, anyLength2,
// any2, ..., anyLengthn, anyn, finalLength, final
@@ -1117,8 +1238,8 @@
normalizedList.add((int)initialBytes[i]);
}
}
- if(subAny.size()==0)
- {
+ List<String> subAny = assertion.getAny();
+ if (subAny.size() == 0) {
normalizedList.add(0);
}
else
@@ -1136,7 +1257,8 @@
}
}
}
- if(subFinal ==null)
+ String subFinal = assertion.getFinal();
+ if (subFinal == null)
{
normalizedList.add(0);
}
@@ -1238,7 +1360,7 @@
}
assertPos = assertPos + anyLength;
}
- }
+ }
int finalLength = 0xFF & assertionBytes[assertPos++];
if(finalLength!=0)
@@ -1267,23 +1389,371 @@
}
return ConditionResult.TRUE;
- }
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public final Collection<ExtensibleIndexer> getIndexers(IndexConfig config)
+ {
+ Collection<ExtensibleIndexer> indexers =
+ new ArrayList<ExtensibleIndexer>();
+ int substrLength = 6; //Default substring length;
+ if(subIndexer == null)
+ {
+ if(config != null)
+ {
+ substrLength = config.getSubstringLength();
+ }
+ subIndexer = new CollationSubstringExtensibleIndexer(this,
+ substrLength);
+ }
+ else
+ {
+ if(config !=null)
+ {
+ if(config.getSubstringLength() !=subIndexer.gerSubstringLength())
+ {
+ subIndexer.setSubstringLength(substrLength);
+ }
+ }
+ }
+
+ if(indexer == null)
+ {
+ indexer = new CollationSharedExtensibleIndexer(this);
+ }
+ indexers.add(subIndexer);
+ indexers.add(indexer);
+ return indexers;
+ }
+
+
+
+ /**
+ * Decomposes an attribute value into a set of substring index keys.
+ *
+ * @param attValue Tthe normalized attribute value
+ * @param set A set into which the keys will be inserted.
+ */
+ private void subtringKeys(ByteString attValue,
+ Set<byte[]> keys)
+ {
+ String value = attValue.stringValue();
+ int keyLength = subIndexer.gerSubstringLength();
+ for (int i = 0, remain = value.length(); remain > 0; i++, remain--)
+ {
+ int len = Math.min(keyLength, remain);
+ byte[] keyBytes = makeSubstringKey(value, i, len);
+ keys.add(keyBytes);
+ }
+ }
+
+
+
+ /**
+ * Decomposes an attribute value into a set of substring index keys.
+ *
+ * @param value The normalized attribute value
+ * @param modifiedKeys The map into which the modified
+ * keys will be inserted.
+ * @param insert <code>true</code> if generated keys should
+ * be inserted or <code>false</code> otherwise.
+ */
+ private void substringKeys(ByteString attValue,
+ Map<byte[], Boolean> modifiedKeys,
+ Boolean insert)
+ {
+ String value = attValue.stringValue();
+ int keyLength = subIndexer.gerSubstringLength();
+ for (int i = 0, remain = value.length(); remain > 0; i++, remain--)
+ {
+ int len = Math.min(keyLength, remain);
+ byte[] keyBytes = makeSubstringKey(value, i, len);
+ Boolean cinsert = modifiedKeys.get(keyBytes);
+ if (cinsert == null)
+ {
+ modifiedKeys.put(keyBytes, insert);
+ }
+ else if (!cinsert.equals(insert))
+ {
+ modifiedKeys.remove(keyBytes);
+ }
+ }
+ }
+
+
+
+ /**
+ * Makes a byte array representing a substring index key for
+ * one substring of a value.
+ *
+ * @param value The String containing the value.
+ * @param pos The starting position of the substring.
+ * @param len The length of the substring.
+ * @return A byte array containing a substring key.
+ */
+ private byte[] makeSubstringKey(String value, int pos, int len)
+ {
+ String sub = value.substring(pos, pos + len);
+ CollationKey col = collator.getCollationKey(sub);
+ byte[] origKey = col.toByteArray();
+ byte[] newKey = new byte[origKey.length - 4];
+ System.arraycopy(origKey, 0, newKey, 0, newKey.length);
+ return newKey;
+ }
+
+
+
+ /**
+ * Uses an equality index to retrieve the entry IDs that might contain a
+ * given initial substring.
+ * @param bytes A normalized initial substring of an attribute value.
+ * @return The candidate entry IDs.
+ */
+ private <T> T matchInitialSubstring(String value,
+ IndexQueryFactory<T> factory)
+ {
+ byte[] lower = makeSubstringKey(value, 0, value.length());
+ byte[] upper = new byte[lower.length];
+ System.arraycopy(lower, 0, upper, 0, lower.length);
+
+ for (int i = upper.length - 1; i >= 0; i--)
+ {
+ if (upper[i] == 0xFF)
+ {
+ // We have to carry the overflow to the more significant byte.
+ upper[i] = 0;
+ }
+ else
+ {
+ // No overflow, we can stop.
+ upper[i] = (byte) (upper[i] + 1);
+ break;
+ }
+ }
+ //Use the shared equality indexer.
+ return factory.createRangeMatchQuery(
+ indexer.getExtensibleIndexID(),
+ lower,
+ upper,
+ true,
+ false);
+ }
+
+
+
+ /**
+ * Retrieves the Index Records that might contain a given substring.
+ * @param value A String representing the attribute value.
+ * @param factory An IndexQueryFactory which issues calls to the backend.
+ * @param substrLength The length of the substring.
+ * @return The candidate entry IDs.
+ */
+ private <T> T matchSubstring(String value,
+ IndexQueryFactory<T> factory)
+ {
+ T intersectionQuery = null;
+ int substrLength = subIndexer.gerSubstringLength();
+
+ if (value.length() < substrLength)
+ {
+ byte[] lower = makeSubstringKey(value, 0, value.length());
+ byte[] upper = makeSubstringKey(value, 0, value.length());
+ for (int i = upper.length - 1; i >= 0; i--)
+ {
+ if (upper[i] == 0xFF)
+ {
+ // We have to carry the overflow to the more significant byte.
+ upper[i] = 0;
+ } else
+ {
+ // No overflow, we can stop.
+ upper[i] = (byte) (upper[i] + 1);
+ break;
+ }
+ }
+ // Read the range: lower <= keys < upper.
+ intersectionQuery =
+ factory.createRangeMatchQuery(
+ subIndexer.getExtensibleIndexID(),
+ lower,
+ upper,
+ true,
+ false);
+ }
+ else
+ {
+ List<T> queryList = new ArrayList<T>();
+ Set<byte[]> set =
+ new TreeSet<byte[]>(new AttributeIndex.KeyComparator());
+ for (int first = 0, last = substrLength;
+ last <= value.length(); first++, last++)
+ {
+ byte[] keyBytes;
+ keyBytes = makeSubstringKey(value, first, substrLength);
+ set.add(keyBytes);
+ }
+
+ for (byte[] keyBytes : set)
+ {
+ T single = factory.createExactMatchQuery(
+ subIndexer.getExtensibleIndexID(),
+ keyBytes);
+ queryList.add(single);
+ }
+ intersectionQuery =
+ factory.createIntersectionQuery(queryList);
+ }
+ return intersectionQuery;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public <T> T createIndexQuery(ByteString assertionValue,
+ IndexQueryFactory<T> factory) throws DirectoryException
+ {
+ Assertion assertion = parseAssertion(assertionValue);
+ String subInitial = assertion.getInitial();
+ List<String> subAny = assertion.getAny();
+ String subFinal = assertion.getFinal();
+ List<T> queries = new ArrayList<T>();
+
+ if (subInitial == null && subAny.size() == 0 && subFinal == null)
+ {
+ //Can happen with a filter like "cn:en.6:=*".
+ //Just return an empty record.
+ return factory.createMatchAllQuery();
+ }
+ List<String> elements = new ArrayList<String>();
+ if (subInitial != null)
+ {
+ //Always use the shared indexer for initial match.
+ T query = matchInitialSubstring(subInitial, factory);
+ queries.add(query);
+ }
+
+ if (subAny != null && subAny.size() > 0)
+ {
+ elements.addAll(subAny);
+ }
+
+ if (subFinal != null)
+ {
+ elements.add(subFinal);
+ }
+
+
+ for (String element : elements)
+ {
+ queries.add(matchSubstring(element, factory));
+ }
+ return factory.createIntersectionQuery(queries);
+ }
}
- /**
- *Collation rule for less-than matching rule.
- */
- private final class CollationLessThanMatchingRule
- extends ExtensibleMatchingRule
+
+
+ /**
+ *An abstract Collation rule for Ordering matching rule.
+ */
+ private abstract class CollationOrderingMatchingRule
+ extends CollationMatchingRule
{
- //Names for this class.
- private final Collection<String> names;
+ /**
+ * Constructs a new CollationOrderingMatchingRule.
+ *
+ * @param nOID OID of the collation matching rule
+ * @param names names of this matching rule
+ * @param locale Locale of the collation matching rule
+ */
+ private CollationOrderingMatchingRule(String nOID,
+ Collection<String> names, Locale locale)
+ {
+ super(nOID,names,locale);
+ }
- //Collator for performing equality match.
- private final Collator collator;
- //Numeric OID of the rule.
- private final String nOID;
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public ByteString normalizeValue(ByteString value)
+ throws DirectoryException
+ {
+ CollationKey key = collator.getCollationKey(value.stringValue());
+ return new ASN1OctetString(key.toByteArray());
+ }
+
+
+
+ /**
+ * Compares the first value to the second and returns a value that
+ * indicates their relative order.
+ *
+ * @param b1 The normalized form of the first value to
+ * compare.
+ * @param b2 The normalized form of the second value to
+ * compare.
+ *
+ * @return A negative integer if {@code value1} should come before
+ * {@code value2} in ascending order, a positive integer if
+ * {@code value1} should come after {@code value2} in
+ * ascending order, or zero if there is no difference
+ * between the values with regard to ordering.
+ */
+ protected int compare(byte[] b1, byte[] b2) {
+ //Compare values using byte arrays.
+ int minLength = Math.min(b1.length, b2.length);
+
+ for (int i=0; i < minLength; i++)
+ {
+ int firstByte = 0xFF & ((int)b1[i]);
+ int secondByte = 0xFF & ((int)b2[i]);
+
+ if (firstByte == secondByte)
+ {
+ continue;
+ }
+ else if (firstByte < secondByte)
+ {
+ return -1;
+ }
+ else if (firstByte > secondByte)
+ {
+ return 1;
+ }
+ }
+
+ if (b1.length == b2.length)
+ {
+ return 0;
+ }
+ else if (b1.length < b2.length)
+ {
+ return -1;
+ }
+ else
+ {
+ return 1;
+ }
+ }
+ }
+
+ /**
+ * Collation matching rule for Less-than matching rule.
+ */
+ private final class CollationLessThanMatchingRule
+ extends CollationOrderingMatchingRule
+ {
/**
* Constructs a new CollationLessThanMatchingRule.
@@ -1293,160 +1763,24 @@
* @param locale Locale of the collation matching rule
*/
private CollationLessThanMatchingRule(String nOID,
- Collection<String> names,Locale locale)
+ Collection<String> names, Locale locale)
{
- super();
- this.names = names;
- this.collator =createCollator(locale);
- this.nOID = nOID;
+ super(nOID, names, locale);
}
- /**
- * {@inheritDoc}
- */
- @Override
- public String getName()
- {
- //Concatenate all the names and return.
- StringBuilder builder = new StringBuilder();
- for(String name: getAllNames())
- {
- builder.append(name);
- builder.append("\b");
- }
- return builder.toString();
- }
-
-
-
-
- /**
- * {@inheritDoc}
- */
- @Override
- public Collection<String> getAllNames()
- {
- return Collections.unmodifiableCollection(names);
- }
-
-
-
-
- /**
- * {@inheritDoc}
- */
- @Override
- public String getOID()
- {
- return nOID;
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- @Override
- public String getDescription()
- {
- // There is no standard description for this matching rule.
- return null;
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- @Override
- public String getSyntaxOID()
- {
- return SYNTAX_DIRECTORY_STRING_OID;
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- @Override
- public ByteString normalizeValue(ByteString value)
- throws DirectoryException
- {
- CollationKey key = collator.getCollationKey(value.stringValue());
- return new ASN1OctetString(key.toByteArray());
- }
-
-
-
- /**
- * Compares the first value to the second and returns a value that
- * indicates their relative order.
- *
- * @param b1 The normalized form of the first value to
- * compare.
- * @param b2 The normalized form of the second value to
- * compare.
- *
- * @return A negative integer if {@code value1} should come before
- * {@code value2} in ascending order, a positive integer if
- * {@code value1} should come after {@code value2} in
- * ascending order, or zero if there is no difference
- * between the values with regard to ordering.
- */
- private int compare(byte[] b1, byte[] b2)
- {
- //Compare values using byte arrays.
- int minLength = Math.min(b1.length, b2.length);
-
- for (int i=0; i < minLength; i++)
- {
- int firstByte = 0xFF & ((int)b1[i]);
- int secondByte = 0xFF & ((int)b2[i]);
-
- if (firstByte == secondByte)
- {
- continue;
- }
- else if (firstByte < secondByte)
- {
- return -1;
- }
- else if (firstByte > secondByte)
- {
- return 1;
- }
- }
-
- if (b1.length == b2.length)
- {
- return 0;
- }
- else if (b1.length < b2.length)
- {
- return -1;
- }
- else
- {
- return 1;
- }
- }
-
-
-
/**
* {@inheritDoc}
*/
@Override
public ConditionResult valuesMatch(ByteString attributeValue,
- ByteString assertionValue)
+ ByteString assertionValue)
{
- int ret = compare(attributeValue.value(),assertionValue.value());
+ int ret = compare(attributeValue.value(), assertionValue.value());
- if(ret <0)
+ if (ret < 0)
{
return ConditionResult.TRUE;
}
@@ -1455,24 +1789,35 @@
return ConditionResult.FALSE;
}
}
+
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public <T> T createIndexQuery(ByteString assertionValue,
+ IndexQueryFactory<T> factory) throws DirectoryException
+ {
+ byte[] lower = new byte[0];
+ byte[] upper = normalizeValue(assertionValue).value();
+ return factory.createRangeMatchQuery(indexer.getExtensibleIndexID(),
+ lower,
+ upper,
+ false,
+ false);
+ }
}
+
/**
- * Collation rule for less-than-equal-to matching rule.
- */
+ * Collation rule for less-than-equal-to matching rule.
+ */
private final class CollationLessThanOrEqualToMatchingRule
- extends ExtensibleMatchingRule
+ extends CollationOrderingMatchingRule
{
- //Names for this class.
- private final Collection<String> names;
-
- //Collator for performing equality match.
- private final Collator collator;
-
- //Numeric OID of the rule.
- private final String nOID;
-
/**
* Constructs a new CollationLessThanOrEqualToMatchingRule.
@@ -1482,161 +1827,25 @@
* @param locale Locale of the collation matching rule
*/
private CollationLessThanOrEqualToMatchingRule(String nOID,
- Collection<String> names,
- Locale locale)
+ Collection<String> names,
+ Locale locale)
{
- super();
- this.names = names;
- this.collator =createCollator(locale);
- this.nOID = nOID;
+ super(nOID, names, locale);
}
- /**
- * {@inheritDoc}
- */
- @Override
- public String getName()
- {
- //Concatenate all the names and return.
- StringBuilder builder = new StringBuilder();
- for(String name: getAllNames())
- {
- builder.append(name);
- builder.append("\b");
- }
- return builder.toString();
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- @Override
- public Collection<String> getAllNames()
- {
- return Collections.unmodifiableCollection(names);
- }
-
-
-
-
- /**
- * {@inheritDoc}
- */
- @Override
- public String getOID()
- {
- return nOID;
- }
-
-
-
-
- /**
- * {@inheritDoc}
- */
- @Override
- public String getDescription()
- {
- // There is no standard description for this matching rule.
- return null;
- }
-
-
-
-
- /**
- * {@inheritDoc}
- */
- @Override
- public String getSyntaxOID()
- {
- return SYNTAX_DIRECTORY_STRING_OID;
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- @Override
- public ByteString normalizeValue(ByteString value)
- throws DirectoryException
- {
- CollationKey key = collator.getCollationKey(value.stringValue());
- return new ASN1OctetString(key.toByteArray());
- }
-
-
-
- /**
- * Compares the first value to the second and returns a value that
- * indicates their relative order.
- *
- * @param b1 The normalized form of the first value to
- * compare.
- * @param b2 The normalized form of the second value to
- * compare.
- *
- * @return A negative integer if {@code value1} should come before
- * {@code value2} in ascending order, a positive integer if
- * {@code value1} should come after {@code value2} in
- * ascending order, or zero if there is no difference
- * between the values with regard to ordering.
- */
- public int compare(byte[] b1, byte[] b2)
- {
- //Compare values using byte arrays.
- int minLength = Math.min(b1.length, b2.length);
-
- for (int i=0; i < minLength; i++)
- {
- int firstByte = 0xFF & ((int)b1[i]);
- int secondByte = 0xFF & ((int)b2[i]);
-
- if (firstByte == secondByte)
- {
- continue;
- }
- else if (firstByte < secondByte)
- {
- return -1;
- }
- else if (firstByte > secondByte)
- {
- return 1;
- }
- }
-
- if (b1.length == b2.length)
- {
- return 0;
- }
- else if (b1.length < b2.length)
- {
- return -1;
- }
- else
- {
- return 1;
- }
- }
-
-
/**
* {@inheritDoc}
*/
@Override
public ConditionResult valuesMatch(ByteString attributeValue,
- ByteString assertionValue)
+ ByteString assertionValue)
{
- int ret = compare(attributeValue.value(),assertionValue.value());
+ int ret = compare(attributeValue.value(), assertionValue.value());
- if(ret <= 0)
+ if (ret <= 0)
{
return ConditionResult.TRUE;
}
@@ -1645,25 +1854,37 @@
return ConditionResult.FALSE;
}
}
+
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public <T> T createIndexQuery(ByteString assertionValue,
+ IndexQueryFactory<T> factory)
+ throws DirectoryException
+ {
+ byte[] lower = new byte[0];
+ byte[] upper = normalizeValue(assertionValue).value();
+ // Read the range: lower < keys <= upper.
+ return factory.createRangeMatchQuery(indexer.getExtensibleIndexID(),
+ lower,
+ upper,
+ false,
+ true);
+ }
}
- /**
- * Collation rule for greater-than matching rule.
- */
+ /**
+ * Collation rule for greater-than matching rule.
+ */
private final class CollationGreaterThanMatchingRule
- extends ExtensibleMatchingRule
+ extends CollationOrderingMatchingRule
{
- //Names for this class.
- private final Collection<String> names;
-
- //Collator for performing equality match.
- private final Collator collator;
-
- //Numeric OID of the rule.
- private final String nOID;
-
/**
* Constructs a new CollationGreaterThanMatchingRule.
@@ -1673,147 +1894,9 @@
* @param locale Locale of the collation matching rule
*/
private CollationGreaterThanMatchingRule(String nOID,
- Collection<String> names,Locale locale)
+ Collection<String> names, Locale locale)
{
- super();
- this.names = names;
- this.collator =createCollator(locale);
- this.nOID = nOID;
- }
-
-
-
-
- /**
- * {@inheritDoc}
- */
- @Override
- public String getName()
- {
- //Concatenate all the names and return.
- StringBuilder builder = new StringBuilder();
- for(String name: getAllNames())
- {
- builder.append(name);
- builder.append("\b");
- }
- return builder.toString();
- }
-
-
-
-
- /**
- * {@inheritDoc}
- */
- @Override
- public Collection<String> getAllNames()
- {
- return Collections.unmodifiableCollection(names);
- }
-
-
-
-
- /**
- * {@inheritDoc}
- */
- @Override
- public String getOID()
- {
- return nOID;
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- @Override
- public String getDescription()
- {
- // There is no standard description for this matching rule.
- return null;
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- @Override
- public String getSyntaxOID()
- {
- return SYNTAX_DIRECTORY_STRING_OID;
- }
-
-
-
-
- /**
- * {@inheritDoc}
- */
- @Override
- public ByteString normalizeValue(ByteString value)
- throws DirectoryException
- {
- CollationKey key = collator.getCollationKey(value.stringValue());
- return new ASN1OctetString(key.toByteArray());
- }
-
-
-
- /**
- * Compares the first value to the second and returns a value that
- * indicates their relative order.
- *
- * @param b1 The normalized form of the first value to
- * compare.
- * @param b2 The normalized form of the second value to
- * compare.
- *
- * @return A negative integer if {@code value1} should come before
- * {@code value2} in ascending order, a positive integer if
- * {@code value1} should come after {@code value2} in
- * ascending order, or zero if there is no difference
- * between the values with regard to ordering.
- */
- public int compare(byte[] b1, byte[] b2)
- {
- //Compare values using byte arrays.
- int minLength = Math.min(b1.length, b2.length);
-
- for (int i=0; i < minLength; i++)
- {
- int firstByte = 0xFF & ((int)b1[i]);
- int secondByte = 0xFF & ((int)b2[i]);
-
- if (firstByte == secondByte)
- {
- continue;
- }
- else if (firstByte < secondByte)
- {
- return -1;
- }
- else if (firstByte > secondByte)
- {
- return 1;
- }
- }
-
- if (b1.length == b2.length)
- {
- return 0;
- }
- else if (b1.length < b2.length)
- {
- return -1;
- }
- else
- {
- return 1;
- }
+ super(nOID, names, locale);
}
@@ -1823,39 +1906,45 @@
*/
@Override
public ConditionResult valuesMatch(ByteString attributeValue,
- ByteString assertionValue)
+ ByteString assertionValue)
{
- int ret = compare(attributeValue.value(),assertionValue.value());
+ int ret = compare(attributeValue.value(), assertionValue.value());
- if(ret > 0)
- {
+ if (ret > 0) {
return ConditionResult.TRUE;
- }
- else
- {
+ } else {
return ConditionResult.FALSE;
}
}
+
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public <T> T createIndexQuery(ByteString assertionValue,
+ IndexQueryFactory<T> factory)
+ throws DirectoryException
+ {
+ byte[] lower = normalizeValue(assertionValue).value();
+ byte[] upper = new byte[0];
+ return factory.createRangeMatchQuery(indexer.getExtensibleIndexID(),
+ lower,
+ upper,
+ false,
+ false);
+ }
}
-
- /**
- * Collation rule for greater-than-equal-to matching rule.
- */
+ /**
+ * Collation rule for greater-than-equal-to matching rule.
+ */
private final class CollationGreaterThanOrEqualToMatchingRule
- extends ExtensibleMatchingRule
+ extends CollationOrderingMatchingRule
{
- //Names for this class.
- private final Collection<String> names;
-
- //Collator for performing equality match.
- private final Collator collator;
-
- //Numeric OID of the rule.
- private final String nOID;
-
-
/**
* Constructs a new CollationGreaterThanOrEqualToMatchingRule.
*
@@ -1864,143 +1953,31 @@
* @param locale Locale of the collation matching rule
*/
private CollationGreaterThanOrEqualToMatchingRule(String nOID,
- Collection<String> names,
- Locale locale)
+ Collection<String> names,
+ Locale locale)
{
- super();
- this.names = names;
- this.collator =createCollator(locale);
- this.nOID = nOID;
+ super(nOID, names, locale);
}
- /**
- * {@inheritDoc}
- */
+
+ /**
+ * {@inheritDoc}
+ */
@Override
- public String getName()
+ public ConditionResult valuesMatch(ByteString attributeValue,
+ ByteString assertionValue)
{
- //Concatenate all the names and return.
- StringBuilder builder = new StringBuilder();
- for(String name: getAllNames())
+ int ret = compare(attributeValue.value(),assertionValue.value());
+
+ if (ret >= 0)
{
- builder.append(name);
- builder.append("\b");
- }
- return builder.toString();
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- @Override
- public Collection<String> getAllNames()
- {
- return Collections.unmodifiableCollection(names);
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- @Override
- public String getOID()
- {
- return nOID;
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- @Override
- public String getDescription()
- {
- // There is no standard description for this matching rule.
- return null;
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- @Override
- public String getSyntaxOID()
- {
- return SYNTAX_DIRECTORY_STRING_OID;
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- @Override
- public ByteString normalizeValue(ByteString value)
- throws DirectoryException
- {
- CollationKey key = collator.getCollationKey(value.stringValue());
- return new ASN1OctetString(key.toByteArray());
- }
-
-
-
- /**
- * Compares the first value to the second and returns a value that
- * indicates their relative order.
- *
- * @param b1 The normalized form of the first value to
- * compare.
- * @param b2 The normalized form of the second value to
- * compare.
- *
- * @return A negative integer if {@code value1} should come before
- * {@code value2} in ascending order, a positive integer if
- * {@code value1} should come after {@code value2} in
- * ascending order, or zero if there is no difference
- * between the values with regard to ordering.
- */
- public int compare(byte[] b1, byte[] b2)
- {
- //Compare values using byte arrays.
- int minLength = Math.min(b1.length, b2.length);
-
- for (int i=0; i < minLength; i++)
- {
- int firstByte = 0xFF & ((int)b1[i]);
- int secondByte = 0xFF & ((int)b2[i]);
-
- if (firstByte == secondByte)
- {
- continue;
- }
- else if (firstByte < secondByte)
- {
- return -1;
- }
- else if (firstByte > secondByte)
- {
- return 1;
- }
- }
-
- if (b1.length == b2.length)
- {
- return 0;
- }
- else if (b1.length < b2.length)
- {
- return -1;
+ return ConditionResult.TRUE;
}
else
{
- return 1;
+ return ConditionResult.FALSE;
}
}
@@ -2010,27 +1987,228 @@
* {@inheritDoc}
*/
@Override
- public ConditionResult valuesMatch(ByteString attributeValue,
- ByteString assertionValue)
+ public <T> T createIndexQuery(ByteString assertionValue,
+ IndexQueryFactory<T> factory)
+ throws DirectoryException
{
- int ret = compare(attributeValue.value(),assertionValue.value());
-
- if(ret >= 0)
- {
- return ConditionResult.TRUE;
- }
- else
- {
- return ConditionResult.FALSE;
- }
+ byte[] lower = normalizeValue(assertionValue).value();
+ byte[] upper = new byte[0];
+ // Read the range: lower <= keys < upper.
+ return factory.createRangeMatchQuery(indexer.getExtensibleIndexID(),
+ lower,
+ upper,
+ true,
+ false);
}
}
- /**
- * A utility class for extracting the OID and Language Tag from the
- * configuration entry.
- */
+ /**
+ * Extensible Indexer class for Collation Matching rules which share the
+ * same index. This Indexer is shared by Equality and Ordering Collation
+ * Matching Rules.
+ */
+ private final class CollationSharedExtensibleIndexer
+ extends ExtensibleIndexer
+ {
+
+ /**
+ * The Extensible Matching Rule.
+ */
+ private final CollationMatchingRule matchingRule;
+
+
+
+ /**
+ * Creates a new instance of CollationSharedExtensibleIndexer.
+ *
+ * @param matchingRule The Collation Matching Rule.
+ */
+ private CollationSharedExtensibleIndexer(
+ CollationMatchingRule matchingRule)
+ {
+ this.matchingRule = matchingRule;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getExtensibleIndexID()
+ {
+ return EXTENSIBLE_INDEXER_ID_SHARED;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public final void getKeys(AttributeValue value,
+ Set<byte[]> keys)
+ {
+ ByteString key;
+ try
+ {
+ key = matchingRule.normalizeValue(value.getValue());
+ keys.add(key.value());
+ }
+ catch (DirectoryException de)
+ {
+ }
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public final void getKeys(AttributeValue value,
+ Map<byte[], Boolean> modifiedKeys,
+ Boolean insert)
+ {
+ Set<byte[]> keys = new HashSet<byte[]>();
+ getKeys(value, keys);
+ for (byte[] key : keys)
+ {
+ Boolean cInsert = modifiedKeys.get(key);
+ if (cInsert == null)
+ {
+ modifiedKeys.put(key, insert);
+ }
+ else if (!cInsert.equals(insert))
+ {
+ modifiedKeys.remove(key);
+ }
+ }
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getPreferredIndexName()
+ {
+ return matchingRule.getIndexName();
+ }
+ }
+
+ /**
+ * Extensible Indexer class for Collation Substring Matching rules.
+ * This Indexer is used by Substring Collation Matching Rules.
+ */
+ private final class CollationSubstringExtensibleIndexer
+ extends ExtensibleIndexer
+ {
+ //The CollationSubstringMatching Rule.
+ private final CollationSubstringMatchingRule matchingRule;
+
+
+
+ //The substring length.
+ private int substringLen;
+
+
+
+ /**
+ * Creates a new instance of CollationSubstringExtensibleIndexer.
+ *
+ * @param matchingRule The CollationSubstringMatching Rule.
+ * @param substringLen The substring length.
+ */
+ private CollationSubstringExtensibleIndexer(
+ CollationSubstringMatchingRule matchingRule,
+ int substringLen)
+ {
+ this.matchingRule = matchingRule;
+ this.substringLen = substringLen;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void getKeys(AttributeValue value,
+ Set<byte[]> keys)
+ {
+ matchingRule.subtringKeys(value.getValue(),
+ keys);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void getKeys(AttributeValue attValue,
+ Map<byte[], Boolean> modifiedKeys,
+ Boolean insert)
+ {
+ matchingRule.substringKeys(attValue.getValue(),
+ modifiedKeys,
+ insert);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getPreferredIndexName()
+ {
+ return matchingRule.getIndexName();
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getExtensibleIndexID()
+ {
+ return EXTENSIBLE_INDEXER_ID_SUBSTRING;
+ }
+
+
+
+ /**
+ * Returns the substring length.
+ * @return The length of the substring.
+ */
+ private int gerSubstringLength()
+ {
+ return substringLen;
+ }
+
+
+
+ /**
+ * Sets the substring length.
+ * @param substringLen The substring length.
+ */
+ private void setSubstringLength(int substringLen)
+ {
+ this.substringLen = substringLen;
+ }
+ }
+
+
+
+ /**
+ * A utility class for extracting the OID and Language Tag from the
+ * configuration entry.
+ */
private final class CollationMapper
{
//OID of the collation rule.
diff --git a/opendj-sdk/opends/src/server/org/opends/server/types/IndexConfig.java b/opendj-sdk/opends/src/server/org/opends/server/types/IndexConfig.java
new file mode 100644
index 0000000..377a386
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/types/IndexConfig.java
@@ -0,0 +1,41 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ * Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ * Copyright 2009 Sun Microsystems, Inc.
+ */
+
+
+package org.opends.server.types;
+
+/**
+ * This class represents the configuration of an index.
+ */
+public abstract class IndexConfig
+{
+ /**
+ * Returns the length of a substring.
+ * @return the length of the substring.
+ */
+ public abstract int getSubstringLength();
+}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/types/Schema.java b/opendj-sdk/opends/src/server/org/opends/server/types/Schema.java
index f969e45..52216f3 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/types/Schema.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/types/Schema.java
@@ -20,9 +20,9 @@
* Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
+ *©
*
- *
- * Copyright 2006-2008 Sun Microsystems, Inc.
+ * Copyright 2006-2009 Sun Microsystems, Inc.
*/
package org.opends.server.types;
@@ -47,6 +47,7 @@
import org.opends.server.api.ApproximateMatchingRule;
import org.opends.server.api.AttributeSyntax;
import org.opends.server.api.EqualityMatchingRule;
+import org.opends.server.api.ExtensibleMatchingRule;
import org.opends.server.api.MatchingRule;
import org.opends.server.api.OrderingMatchingRule;
import org.opends.server.api.SubstringMatchingRule;
@@ -149,6 +150,12 @@
private ConcurrentHashMap<String,SubstringMatchingRule>
substringMatchingRules;
+ // The set of extensible matching rules for this schema, mapped
+ // between the lowercase names and OID for the definition and the
+ // matching rule itself.
+ private ConcurrentHashMap<String,ExtensibleMatchingRule>
+ extensibleMatchingRules;
+
// The set of matching rule uses for this schema, mapped between the
// matching rule for the definition and the matching rule use
// itself.
@@ -242,6 +249,8 @@
new ConcurrentHashMap<String,OrderingMatchingRule>();
substringMatchingRules =
new ConcurrentHashMap<String,SubstringMatchingRule>();
+ extensibleMatchingRules =
+ new ConcurrentHashMap<String,ExtensibleMatchingRule>();
matchingRuleUses =
new ConcurrentHashMap<MatchingRule,MatchingRuleUse>();
ditContentRules =
@@ -1001,6 +1010,11 @@
registerSubstringMatchingRule(
(SubstringMatchingRule) matchingRule, overwriteExisting);
}
+ else if(matchingRule instanceof ExtensibleMatchingRule)
+ {
+ registerExtensibleMatchingRule(
+ (ExtensibleMatchingRule) matchingRule,overwriteExisting);
+ }
else
{
synchronized (matchingRules)
@@ -1834,6 +1848,179 @@
/**
+ * Retrieves the extensible matching rule definitions for this
+ * schema, as a mapping between the lowercase names and OIDs for the
+ * matching rule and the matching rule itself. Each matching rule
+ * may be associated with multiple keys (once for the OID and again
+ * for each name).
+ *
+ * @return The extensible matching rule definitions for this
+ * schema.
+ */
+ public Map<String,ExtensibleMatchingRule>
+ getExtensibleMatchingRules()
+ {
+ return Collections.unmodifiableMap(extensibleMatchingRules);
+ }
+
+
+
+ /**
+ * Retrieves the extensible matching rule definition with the
+ * specified name or OID.
+ *
+ * @param lowerName The name or OID of the matching rule to
+ * retrieve, formatted in all lowercase
+ * characters.
+ *
+ * @return The requested matching rule, or <CODE>null</CODE> if no
+ * extensible matching rule is registered with the
+ * provided name or OID.
+ */
+ public ExtensibleMatchingRule getExtensibleMatchingRule(
+ String lowerName)
+ {
+ return extensibleMatchingRules.get(lowerName);
+ }
+
+
+
+ /**
+ * Registers the provided extensible matching rule with this
+ * schema.
+ *
+ * @param matchingRule The extensible matching rule to
+ * register.
+ * @param overwriteExisting Indicates whether to overwrite an
+ * existing mapping if there are any
+ * conflicts (i.e., another matching rule
+ * with the same OID or name).
+ *
+ * @throws DirectoryException If a conflict is encountered and the
+ * <CODE>overwriteExisting</CODE> flag
+ * is set to <CODE>false</CODE>
+ */
+ public void registerExtensibleMatchingRule(
+ ExtensibleMatchingRule matchingRule,
+ boolean overwriteExisting)
+ throws DirectoryException
+ {
+ synchronized (matchingRules)
+ {
+ if (! overwriteExisting)
+ {
+ String oid = toLowerCase(matchingRule.getOID());
+ if (matchingRules.containsKey(oid))
+ {
+ MatchingRule conflictingRule = matchingRules.get(oid);
+
+ Message message = ERR_SCHEMA_CONFLICTING_MR_OID.
+ get(matchingRule.getNameOrOID(), oid,
+ conflictingRule.getNameOrOID());
+ throw new DirectoryException(
+ ResultCode.CONSTRAINT_VIOLATION, message);
+ }
+
+ for(String name:matchingRule.getAllNames())
+ {
+ if (name != null)
+ {
+ name = toLowerCase(name);
+ if (matchingRules.containsKey(name))
+ {
+ MatchingRule conflictingRule = matchingRules.get(name);
+
+ Message message = ERR_SCHEMA_CONFLICTING_MR_NAME.
+ get(matchingRule.getOID(), name,
+ conflictingRule.getOID());
+ throw new DirectoryException(
+ ResultCode.CONSTRAINT_VIOLATION, message);
+ }
+ }
+ }
+ }
+
+ String oid = toLowerCase(matchingRule.getOID());
+ extensibleMatchingRules.put(oid, matchingRule);
+ matchingRules.put(oid, matchingRule);
+
+ for(String name:matchingRule.getAllNames())
+ {
+ if (name != null)
+ {
+ name = toLowerCase(name);
+ extensibleMatchingRules.put(name, matchingRule);
+ matchingRules.put(name, matchingRule);
+ }
+ }
+ // We'll use an attribute value including the normalized value
+ // rather than the attribute type because otherwise it would use
+ // a very expensive matching rule (OID first component match)
+ // that would kill performance.
+ String valueString = matchingRule.toString();
+ ASN1OctetString rawValue = new ASN1OctetString(valueString);
+ ByteString normValue = normalizationMatchingRule.normalizeValue(
+ new ASN1OctetString(valueString));
+ matchingRuleSet.add(new AttributeValue(rawValue, normValue));
+ }
+ }
+
+
+
+ /**
+ * Deregisters the provided extensible matching rule definition
+ * with this schema.
+ *
+ * @param matchingRule The extensible matching rule to deregister
+ * with this schema.
+ */
+ public void deregisterExtensibleMatchingRule(
+ ExtensibleMatchingRule matchingRule)
+ {
+ synchronized (matchingRules)
+ {
+ String oid = matchingRule.getOID();
+ extensibleMatchingRules.remove(oid, matchingRule);
+ matchingRules.remove(oid, matchingRule);
+
+ for(String name:matchingRule.getAllNames())
+ {
+ if (name != null)
+ {
+ name = toLowerCase(name);
+ extensibleMatchingRules.remove(name, matchingRule);
+ matchingRules.remove(name, matchingRule);
+ }
+ }
+ // We'll use an attribute value including the normalized value
+ // rather than the attribute type because otherwise it would use
+ // a very expensive matching rule (OID first component match)
+ // that would kill performance.
+ try
+ {
+ String valueString = matchingRule.toString();
+ ASN1OctetString rawValue = new ASN1OctetString(valueString);
+ ByteString normValue =
+ normalizationMatchingRule.normalizeValue(
+ new ASN1OctetString(valueString));
+ matchingRuleSet.remove(new AttributeValue(rawValue,
+ normValue));
+ }
+ catch (Exception e)
+ {
+ String valueString = matchingRule.toString();
+ ASN1OctetString rawValue = new ASN1OctetString(valueString);
+ ASN1OctetString normValue =
+ new ASN1OctetString(toLowerCase(valueString));
+ matchingRuleSet.remove(new AttributeValue(rawValue,
+ normValue));
+ }
+ }
+ }
+
+
+
+ /**
* Retrieves the matching rule use definitions for this schema, as a
* mapping between the matching rule for the matching rule use
* definition and the matching rule use itself. Each matching rule
@@ -2942,6 +3129,7 @@
dupSchema.equalityMatchingRules.putAll(equalityMatchingRules);
dupSchema.orderingMatchingRules.putAll(orderingMatchingRules);
dupSchema.substringMatchingRules.putAll(substringMatchingRules);
+ dupSchema.extensibleMatchingRules.putAll(extensibleMatchingRules);
dupSchema.matchingRuleUses.putAll(matchingRuleUses);
dupSchema.ditContentRules.putAll(ditContentRules);
dupSchema.ditStructureRulesByID.putAll(ditStructureRulesByID);
@@ -3579,6 +3767,13 @@
syntaxSet.clear();
syntaxSet = null;
}
+
+ if (extensibleMatchingRules != null)
+ {
+ extensibleMatchingRules.clear();
+ extensibleMatchingRules = null;
+ }
+
}
}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/util/ServerConstants.java b/opendj-sdk/opends/src/server/org/opends/server/util/ServerConstants.java
index d18352c..084cb82 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/util/ServerConstants.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/util/ServerConstants.java
@@ -22,7 +22,7 @@
* CDDL HEADER END
*
*
- * Copyright 2006-2008 Sun Microsystems, Inc.
+ * Copyright 2006-2009 Sun Microsystems, Inc.
*/
package org.opends.server.util;
@@ -2926,6 +2926,22 @@
/**
+ * The extensible indexer identifier string that will be used for a substring
+ * type.
+ */
+ public static final String EXTENSIBLE_INDEXER_ID_SUBSTRING="substring";
+
+
+
+ /**
+ * The extensible indexer identifier string that will be used for a shared
+ * type.
+ */
+ public static final String EXTENSIBLE_INDEXER_ID_SHARED="shared";
+
+
+
+ /**
* The lines that make up the CDDL header. They will not have any prefix, so
* an appropriate prefix may need to be added for some cases (e.g., "# " for
* shell scripts, "rem " for batch files, etc.).
--
Gitblit v1.10.0