From c543bd8a63f66262b7511ba5f90962a497bf0adf Mon Sep 17 00:00:00 2001
From: sin <sin@localhost>
Date: Tue, 21 Jul 2009 04:51:11 +0000
Subject: [PATCH] issue# 4120:Provide an implementation for enumeration syntax

---
 opends/src/server/org/opends/server/types/Schema.java                                  |    1 
 opends/src/messages/messages/backend.properties                                        |    4 
 opends/src/server/org/opends/server/schema/LDAPSyntaxDescriptionSyntax.java            |  448 ++++++++++++++++++++++++++++++++++++-
 opends/src/messages/messages/schema.properties                                         |    6 
 opends/tests/unit-tests-testng/src/server/org/opends/server/schema/LDAPSyntaxTest.java |  227 ++++++++++++++++++
 opends/src/server/org/opends/server/backends/SchemaBackend.java                        |    2 
 opends/src/server/org/opends/server/schema/SchemaConstants.java                        |   14 +
 7 files changed, 684 insertions(+), 18 deletions(-)

diff --git a/opends/src/messages/messages/backend.properties b/opends/src/messages/messages/backend.properties
index 312c05f..c4aa173 100644
--- a/opends/src/messages/messages/backend.properties
+++ b/opends/src/messages/messages/backend.properties
@@ -1145,8 +1145,8 @@
 MILD_ERR_SCHEMA_MODIFY_REMOVE_NO_SUCH_LSD_416=Unable to remove ldap syntax \
  description %s from the server schema because no such ldap syntax \
  description  is defined
-MILD_ERR_ATTR_SYNTAX_INVALID_SUBSTITUTION_SYNTAX_417=The provided value "%s" \
- could not be parsed as a substitution syntax because its OID %s corresponds \
+MILD_ERR_ATTR_SYNTAX_INVALID_LDAP_SYNTAX_417=The provided value "%s" \
+ could not be parsed as an ldap syntax because its OID %s corresponds \
  to an attribute syntax that is already implemented
 MILD_ERR_SCHEMA_MODIFY_CANNOT_DECODE_LDAP_SYNTAX_418=An error occurred while \
  attempting to decode the ldapsyntax description "%s":  %s
diff --git a/opends/src/messages/messages/schema.properties b/opends/src/messages/messages/schema.properties
index 3e18ae2..798246a 100644
--- a/opends/src/messages/messages/schema.properties
+++ b/opends/src/messages/messages/schema.properties
@@ -1009,3 +1009,9 @@
 MILD_WARN_ATTR_SYNTAX_LDAPSYNTAX_REGEX_INVALID_PATTERN_309=The provided value \
   "%s" could not be parsed as a regex syntax because the provided regex \
  pattern "%s" is invalid
+MILD_WARN_ATTR_SYNTAX_LDAPSYNTAX_ENUM_INVALID_VALUE_310=The provided value \
+  "%s" cannot be parsed because it is not allowed by enumeration syntax \
+  with OID "%s"
+MILD_WARN_ATTR_SYNTAX_LDAPSYNTAX_ENUM_DUPLICATE_VALUE_311=The provided value \
+  "%s" cannot be parsed as an enumeration syntax  because it contains a \
+  duplicate value "%s" at position %d
diff --git a/opends/src/server/org/opends/server/backends/SchemaBackend.java b/opends/src/server/org/opends/server/backends/SchemaBackend.java
index 9912785..5ba60ca 100644
--- a/opends/src/server/org/opends/server/backends/SchemaBackend.java
+++ b/opends/src/server/org/opends/server/backends/SchemaBackend.java
@@ -3318,7 +3318,7 @@
     // We allow only unimplemented syntaxes to be substituted.
     if(schema.getSyntax(oid) !=null)
     {
-      Message message = ERR_ATTR_SYNTAX_INVALID_SUBSTITUTION_SYNTAX.get(
+      Message message = ERR_ATTR_SYNTAX_INVALID_LDAP_SYNTAX.get(
               ldapSyntaxDesc.getDefinition(),oid);
       throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION,
                                      message);
diff --git a/opends/src/server/org/opends/server/schema/LDAPSyntaxDescriptionSyntax.java b/opends/src/server/org/opends/server/schema/LDAPSyntaxDescriptionSyntax.java
index 0a890fd..59e90f7 100644
--- a/opends/src/server/org/opends/server/schema/LDAPSyntaxDescriptionSyntax.java
+++ b/opends/src/server/org/opends/server/schema/LDAPSyntaxDescriptionSyntax.java
@@ -29,27 +29,35 @@
 
 
 
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedList;
 import java.util.regex.Pattern;
 
 import org.opends.server.admin.std.server.AttributeSyntaxCfg;
 import org.opends.server.api.ApproximateMatchingRule;
 import org.opends.server.api.AttributeSyntax;
 import org.opends.server.api.EqualityMatchingRule;
-import org.opends.server.api.OrderingMatchingRule;
 import org.opends.server.api.SubstringMatchingRule;
-import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
 import org.opends.messages.Message;
-
-import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
-import static org.opends.server.loggers.ErrorLogger.*;
 import org.opends.server.types.*;
-import static org.opends.messages.SchemaMessages.*;
 import org.opends.messages.MessageBuilder;
-import static org.opends.server.schema.SchemaConstants.*;
-import static org.opends.server.util.StaticUtils.*;
+import org.opends.server.api.AbstractMatchingRule;
+import org.opends.server.api.OrderingMatchingRule;
+import org.opends.server.config.ConfigException;
+import org.opends.server.types.ByteSequence;
+import org.opends.server.types.ByteString;
+import org.opends.server.types.DirectoryException;
 
+import static org.opends.server.schema.SchemaConstants.*;
+import static org.opends.server.schema.StringPrepProfile.*;
+import static org.opends.server.util.ServerConstants.*;
+import static org.opends.server.loggers.debug.DebugLogger.*;
+import static org.opends.server.loggers.ErrorLogger.*;
+import static org.opends.server.util.StaticUtils.*;
+import static org.opends.messages.SchemaMessages.*;
 
 /**
  * This class defines the LDAP syntax description syntax, which is used to
@@ -499,7 +507,7 @@
     String description = descriptionBuffer.toString();
     StringBuilder extBuffer = new StringBuilder();
     LDAPSyntaxDescriptionSyntax syntax = null;
-
+    char c = '\u0000';
     pos = readTokenName(valueStr, extBuffer, pos);
     String lowerTokenName = toLowerCase(extBuffer.toString());
 
@@ -522,8 +530,8 @@
     {
       StringBuilder regexBuffer = new StringBuilder();
       pos = readQuotedString(valueStr, regexBuffer, pos);
-      String regex = regexBuffer.toString();
-      if(regex == null)
+      String regex = regexBuffer.toString().trim();
+      if(regex.length() == 0)
       {
         Message message = WARN_ATTR_SYNTAX_LDAPSYNTAX_REGEX_NO_PATTERN.get(
                valueStr);
@@ -544,6 +552,41 @@
                 message);
       }
     }
+    else if(lowerTokenName.equals("x-enum"))
+    {
+      // The next character must be the opening parenthesis
+      if ((c = valueStr.charAt(pos++)) != '(')
+      {
+
+        Message message =
+                ERR_ATTR_SYNTAX_ATTRSYNTAX_EXPECTED_OPEN_PARENTHESIS.get(
+                        valueStr, pos, String.valueOf(c));
+         throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+                message);
+      }
+      LinkedList<ByteSequence> entries = new LinkedList<ByteSequence>();
+      while(true)
+      {
+        if ((c=valueStr.charAt(pos)) == ')')
+        {
+          pos++;
+          break;
+        }
+        StringBuilder buffer = new StringBuilder();
+        pos = readQuotedString(valueStr, buffer, pos);
+        ByteString entry = ByteString.valueOf(buffer.toString());
+        if(entries.contains(entry))
+        {
+          Message message =
+                WARN_ATTR_SYNTAX_LDAPSYNTAX_ENUM_DUPLICATE_VALUE.get(
+                        valueStr, entry.toString(),pos);
+          throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+                message);
+        }
+        entries.add(entry);
+      }
+      syntax = new EnumSyntax(entries, description, oid);
+    }
     else
     {
       Message message = WARN_ATTR_SYNTAX_LDAPSYNTAX_UNKNOWN_EXT.get(
@@ -552,16 +595,14 @@
               message);
     }
 
-    char c = valueStr.charAt(pos);
-
-    while ((pos < length) && (c == ' '))
+    while ((pos < length) && ((c = valueStr.charAt(pos)) == ' '))
     {
       pos++;
     }
 
     // The next character must be the closing parenthesis and there should not
     // be anything after it (except maybe some spaces).
-    if ((c = valueStr.charAt(pos++)) != ')')
+    if (pos >= length || (c = valueStr.charAt(pos++)) != ')')
     {
 
       Message message =
@@ -889,6 +930,13 @@
             throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
                                          message);
           }
+          //Clean up any space after this.
+          while ((pos < valueStr.length()) &&
+                  ((c = valueStr.charAt(pos)) == ' '))
+          {
+            pos++;
+          }
+
           if(valueStr.charAt(pos) == ')')
               break;
       }
@@ -1232,4 +1280,374 @@
       return approximateMatchingRule;
     }
   }
+
+
+
+  /**
+   * This class provides an enumeration-based mechanism where a new syntax
+   * and its corresponding matching rules can be created on-the-fly. An enum
+   * syntax is an LDAPSyntaxDescriptionSyntax with X-PATTERN extension.
+   */
+  private static class EnumSyntax extends
+          LDAPSyntaxDescriptionSyntax
+  {
+    //Set of read-only enum entries.
+    LinkedList<ByteSequence> entries;
+
+    // The description of this syntax.
+    private String description;
+
+    //The oid of this syntax.
+    private String oid;
+
+    //The equality matching rule.
+    private EqualityMatchingRule equalityMatchingRule;
+
+    //The substring matching rule.
+    private SubstringMatchingRule substringMatchingRule;
+
+    //The ordering matching rule.
+    private OrderingMatchingRule orderingMatchingRule;
+
+    //The approximate matching rule.
+    private ApproximateMatchingRule approximateMatchingRule;
+
+
+    //Creates a new instance of this syntax.
+    private EnumSyntax(LinkedList<ByteSequence> entries,
+            String description,
+            String oid)
+    {
+      super();
+      this.entries = entries;
+      this.description = description;
+      this.oid = oid;
+    }
+
+
+
+     /**
+     * {@inheritDoc}
+     */
+     @Override
+    public String getSyntaxName()
+    {
+      // There is no name for a enum syntax.
+      return null;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+     @Override
+    public String getOID()
+    {
+      return oid;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+     @Override
+    public String getDescription()
+    {
+      return description;
+    }
+
+
+
+     /**
+      * {@inheritDoc}
+      */
+    @Override
+    public void finalizeSyntax()
+    {
+      DirectoryServer.deregisterMatchingRule(orderingMatchingRule);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean valueIsAcceptable(ByteSequence value,
+                                     MessageBuilder invalidReason)
+    {
+      //The value is acceptable if it belongs to the set.
+      boolean isAllowed = entries.contains(value);
+
+      if(!isAllowed)
+      {
+        Message message = WARN_ATTR_SYNTAX_LDAPSYNTAX_ENUM_INVALID_VALUE.get(
+                value.toString(),oid);
+        invalidReason.append(message);
+      }
+
+      return isAllowed;
+    }
+
+
+
+    /**
+     * Retrieves the default equality matching rule that will be used for
+     * attributes with this syntax.
+     *
+     * @return  The default equality matching rule that will be used for
+     *          attributes with this syntax, or <CODE>null</CODE> if equality
+     *          matches will not be allowed for this type by default.
+     */
+    @Override
+    public EqualityMatchingRule getEqualityMatchingRule()
+    {
+      if(equalityMatchingRule == null)
+      {
+        //This has already been verified.
+        equalityMatchingRule =
+                DirectoryServer.getEqualityMatchingRule(EMR_CASE_IGNORE_OID);
+      }
+      return equalityMatchingRule;
+    }
+
+
+
+    /**
+     * Retrieves the default ordering matching rule that will be used for
+     * attributes with this syntax.
+     *
+     * @return  The default ordering matching rule that will be used for
+     *          attributes with this syntax, or <CODE>null</CODE> if ordering
+     *          matches will not be allowed for this type by default.
+     */
+    @Override
+    public OrderingMatchingRule getOrderingMatchingRule()
+    {
+      if(orderingMatchingRule == null)
+      {
+        orderingMatchingRule = new EnumOrderingMatchingRule(this, oid);
+        try
+        {
+          DirectoryServer.registerMatchingRule(orderingMatchingRule, false);
+        }
+        catch(DirectoryException de)
+        {
+          logError(de.getMessageObject());
+        }
+      }
+      return orderingMatchingRule;
+    }
+
+
+
+    /**
+     * Retrieves the default substring matching rule that will be used for
+     * attributes with this syntax.
+     *
+     * @return  The default substring matching rule that will be used for
+     *          attributes with this syntax, or <CODE>null</CODE> if substring
+     *          matches will not be allowed for this type by default.
+     */
+    @Override
+    public SubstringMatchingRule getSubstringMatchingRule()
+    {
+      if(substringMatchingRule == null)
+      {
+        substringMatchingRule =
+                DirectoryServer.getSubstringMatchingRule(SMR_CASE_IGNORE_OID);
+      }
+      return substringMatchingRule;
+    }
+
+
+
+    /**
+     * Retrieves the default approximate matching rule that will be used for
+     * attributes with this syntax.
+     *
+     * @return  The default approximate matching rule that will be used for
+     *          attributes with this syntax, or <CODE>null</CODE> if approximate
+     *          matches will not be allowed for this type by default.
+     */
+    @Override
+    public ApproximateMatchingRule getApproximateMatchingRule()
+    {
+      if(approximateMatchingRule == null)
+      {
+        approximateMatchingRule =
+                DirectoryServer.getApproximateMatchingRule(
+                                    AMR_DOUBLE_METAPHONE_OID);
+      }
+      return approximateMatchingRule;
+    }
+
+
+
+    //Returns the associated data structure containing the enum
+    //values.
+    private LinkedList<ByteSequence> getEnumValues()
+    {
+      return entries;
+    }
+
+
+
+    /**
+      * Implementation of an Enum Ordering matching rule.
+      */
+    private final class EnumOrderingMatchingRule
+       extends AbstractMatchingRule
+       implements OrderingMatchingRule
+    {
+      //The enumeration syntax instance.
+      private EnumSyntax syntax;
+
+
+      //The oid of the matching rule.
+      private String oid;
+
+
+      //The name of the matching rule.
+      private String name;
+
+
+
+      static final long serialVersionUID = -2624642267131703408L;
+
+
+      /**
+       * Creates a new instance.
+       */
+      private EnumOrderingMatchingRule(EnumSyntax syntax,String oid)
+      {
+        super();
+        this.syntax = syntax;
+        this.oid = OMR_OID_GENERIC_ENUM + "." + oid;
+        this.name = OMR_GENERIC_ENUM_NAME + oid;
+      }
+
+
+
+      /**
+      * {@inheritDoc}
+      */
+      public int compare(byte[] arg0, byte[] arg1)
+      {
+        return compareValues(ByteString.wrap(arg0),ByteString.wrap(arg1));
+      }
+
+
+
+      /**
+      * {@inheritDoc}
+      */
+      public int compareValues(ByteSequence value1, ByteSequence value2)
+      {
+        LinkedList<ByteSequence> enumValues = syntax.getEnumValues();
+        return enumValues.indexOf(value1) - enumValues.indexOf(value2);
+      }
+
+
+
+      /**
+       * {@inheritDoc}
+       */
+      @Override
+      public String getName()
+      {
+        return name;
+      }
+
+
+
+       /**
+       * {@inheritDoc}
+       */
+      @Override
+      public Collection<String> getAllNames()
+      {
+        return Collections.singleton(getName());
+      }
+
+
+
+       /**
+       * {@inheritDoc}
+       */
+      @Override
+      public String getOID()
+      {
+        return oid;
+      }
+
+
+
+      /**
+       * {@inheritDoc}
+       */
+      @Override
+      public String getDescription()
+      {
+        return null;
+      }
+
+
+
+      /**
+       * {@inheritDoc}
+       */
+      @Override
+      public String getSyntaxOID()
+      {
+        return SYNTAX_DIRECTORY_STRING_OID;
+      }
+
+
+
+      /**
+       * {@inheritDoc}
+       */
+      @Override
+      public ByteString normalizeValue(ByteSequence value)
+              throws DirectoryException
+      {
+        StringBuilder buffer = new StringBuilder();
+        prepareUnicode(buffer, value, TRIM, CASE_FOLD);
+
+        int bufferLength = buffer.length();
+        if (bufferLength == 0)
+        {
+          if (value.length() > 0)
+          {
+            // This should only happen if the value is composed entirely
+            // of spaces. In that case, the normalized value is a single space.
+            return SINGLE_SPACE_VALUE;
+          }
+          else
+          {
+            // The value is empty, so it is already normalized.
+            return ByteString.empty();
+          }
+        }
+
+
+        // Replace any consecutive spaces with a single space.
+        for (int pos = bufferLength-1; pos > 0; pos--)
+        {
+          if (buffer.charAt(pos) == ' ')
+          {
+            if (buffer.charAt(pos-1) == ' ')
+            {
+              buffer.delete(pos, pos+1);
+            }
+          }
+        }
+
+        return ByteString.valueOf(buffer.toString());
+      }
+    }
+  }
 }
diff --git a/opends/src/server/org/opends/server/schema/SchemaConstants.java b/opends/src/server/org/opends/server/schema/SchemaConstants.java
index 9e51258..118ac9a 100644
--- a/opends/src/server/org/opends/server/schema/SchemaConstants.java
+++ b/opends/src/server/org/opends/server/schema/SchemaConstants.java
@@ -667,6 +667,20 @@
 
 
   /**
+   * The name for the enumOrderingMatch ordering matching rule.
+   */
+  public static final String OMR_GENERIC_ENUM_NAME = "enumOrderingMatch";
+
+
+
+  /**
+   * The oid for the generic enum syntax ordering matching rule.
+   */
+  public static final String OMR_OID_GENERIC_ENUM="1.3.6.1.4.1.26027.1.4.8";
+
+
+
+  /**
    * The name for the caseExactSubstringsMatch substring matching rule.
    */
   public static final String SMR_CASE_EXACT_NAME = "caseExactSubstringsMatch";
diff --git a/opends/src/server/org/opends/server/types/Schema.java b/opends/src/server/org/opends/server/types/Schema.java
index e5a3f22..67094d8 100644
--- a/opends/src/server/org/opends/server/types/Schema.java
+++ b/opends/src/server/org/opends/server/types/Schema.java
@@ -1041,6 +1041,7 @@
       {
         //Get rid of this from the virtual ldapsyntaxes.
         deregisterSyntax(syntax.getLdapSyntaxDescriptionSyntax());
+        syntax.getLdapSyntaxDescriptionSyntax().finalizeSyntax();
       }
       catch (Exception e)
       {
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/LDAPSyntaxTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/LDAPSyntaxTest.java
index e7fabb7..62664aa 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/LDAPSyntaxTest.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/LDAPSyntaxTest.java
@@ -40,6 +40,7 @@
 import org.opends.server.types.Attribute;
 import org.opends.server.types.AttributeValue;
 import org.opends.server.types.ByteString;
+import org.opends.server.types.DN;
 import org.opends.server.types.DereferencePolicy;
 import org.opends.server.types.Entry;
 import org.opends.server.types.ResultCode;
@@ -361,6 +362,7 @@
     try
     {
       addRegexSyntax();
+      TestCaseUtils.initializeTestBackend(true);
       //This addition should go through.
       TestCaseUtils.addEntry(
         "dn: cn=test,o=test",
@@ -403,6 +405,178 @@
 
 
 
+    /**
+    * Tests whether it is possible to add values after an enum syntax
+    * has been added.
+    *
+    * @throws java.lang.Exception
+    */
+  @Test()
+  public void testEnumSyntaxAddValues() throws Exception
+  {
+    try
+    {
+      addEnumSyntax();
+      TestCaseUtils.initializeTestBackend(true);
+
+      //This addition should fail because it doesn't match the pattern.
+      Entry entry = TestCaseUtils.makeEntry(
+      "dn: cn=syntax-test,o=test",
+      "objectclass: person",
+      "objectclass: testOC",
+      "cn: syntax-test",
+      "sn: xyz",
+      "test-attr-enum: arbit-day");
+      InternalClientConnection conn =
+         InternalClientConnection.getRootConnection();
+
+    AddOperation addOperation = conn.processAdd(entry.getDN(),
+                                     entry.getObjectClasses(),
+                                     entry.getUserAttributes(),
+                                     entry.getOperationalAttributes());
+    assertEquals(addOperation.getResultCode(),
+            ResultCode.INVALID_ATTRIBUTE_SYNTAX);
+
+      //This addition should go through.
+      TestCaseUtils.addEntry(
+        "dn: cn=syntax-test,o=test",
+        "objectclass: person",
+        "objectclass: testOC",
+        "cn: syntax-test",
+        "sn: xyz",
+        "test-attr-enum: sunday");
+    }
+    finally
+    {
+      deleteEnumSyntax();
+    }
+  }
+
+
+
+  /**
+   * Tests the equality-based search using enum syntax.
+   *
+   * @throws java.lang.Exception
+   */
+  @Test()
+  public void testEnumSyntaxEqualitySearch() throws Exception
+  {
+    try
+    {
+      addEnumSyntax();
+      //This addition should go through.
+      TestCaseUtils.initializeTestBackend(true);
+      TestCaseUtils.addEntry(
+        "dn: cn=test,o=test",
+        "objectclass: person",
+        "objectclass: testOC",
+        "cn: test",
+        "sn: xyz",
+        "test-attr-enum: wednesday");
+
+      InternalClientConnection conn =
+      InternalClientConnection.getRootConnection();
+
+      InternalSearchOperation searchOperation =
+           new InternalSearchOperation(
+                conn,
+                InternalClientConnection.nextOperationID(),
+                InternalClientConnection.nextMessageID(),
+                null,
+                ByteString.valueOf("cn=test,o=test"),
+                SearchScope.WHOLE_SUBTREE,
+                DereferencePolicy.NEVER_DEREF_ALIASES,
+                Integer.MAX_VALUE,
+                Integer.MAX_VALUE,
+                false,
+                LDAPFilter.decode("test-attr-enum=wednesday"),
+                null, null);
+
+      searchOperation.run();
+      assertEquals(searchOperation.getResultCode(), ResultCode.SUCCESS);
+      List<SearchResultEntry> entries = searchOperation.getSearchEntries();
+      SearchResultEntry e = entries.get(0);
+      //An entry must be returned.
+      assertNotNull(e);
+    }
+    finally
+    {
+      deleteEnumSyntax();
+    }
+  }
+
+
+
+  /**
+   * Tests the ordering-based search using enum syntax.
+   *
+   * @throws java.lang.Exception
+   */
+  @Test()
+  public void testEnumSyntaxOrderingSearch() throws Exception
+  {
+    try
+    {
+      addEnumSyntax();
+      TestCaseUtils.initializeTestBackend(true);
+      //This addition should go through.
+      TestCaseUtils.addEntries(
+        "dn: cn=test1,o=test",
+        "objectclass: person",
+        "objectclass: testOC",
+        "cn: test1",
+        "sn: xyz",
+        "test-attr-enum: sunday",
+        "",
+        "dn: cn=test2,o=test",
+        "objectclass: person",
+        "objectclass: testOC",
+        "cn: test2",
+        "sn: xyz",
+        "test-attr-enum: monday",
+        "",
+        "dn: cn=test3,o=test",
+        "objectclass: person",
+        "objectclass: testOC",
+        "cn: test3",
+        "sn: xyz",
+        "test-attr-enum: tuesday");
+
+      InternalClientConnection conn =
+      InternalClientConnection.getRootConnection();
+
+      InternalSearchOperation searchOperation =
+           new InternalSearchOperation(
+                conn,
+                InternalClientConnection.nextOperationID(),
+                InternalClientConnection.nextMessageID(),
+                null,
+                ByteString.valueOf("o=test"),
+                SearchScope.WHOLE_SUBTREE,
+                DereferencePolicy.NEVER_DEREF_ALIASES,
+                Integer.MAX_VALUE,
+                Integer.MAX_VALUE,
+                false,
+                LDAPFilter.decode("test-attr-enum>=tuesday"),
+                null, null);
+
+      searchOperation.run();
+      assertEquals(searchOperation.getResultCode(), ResultCode.SUCCESS);
+      List<SearchResultEntry> entries = searchOperation.getSearchEntries();
+      SearchResultEntry e = entries.get(0);
+      //An entry must be returned.
+      assertNotNull(e);
+      assertTrue(e.getDN().equals(DN.decode("cn=test1,o=test")));
+    }
+    finally
+    {
+      deleteEnumSyntax();
+    }
+  }
+
+
+
   //Parses the OID from the syntax defitions.
   private String getOIDFromLdapSyntax(String valueStr)
   {
@@ -515,4 +689,57 @@
 
     assertTrue(resultCode==0);
   }
+
+
+
+     //Adds an enum syntax to the schema.
+  private void addEnumSyntax() throws Exception
+  {
+    //Add the enum syntax.
+    int resultCode = TestCaseUtils.applyModifications(true,
+    "dn: cn=schema",
+    "changetype: modify",
+    "add: ldapsyntaxes",
+    "ldapSyntaxes: ( 3.3.3  DESC 'Day Of The Week'  " +
+            "X-ENUM  ( 'monday' 'tuesday'   'wednesday'  'thursday'  'friday'  'saturday' 'sunday') )");
+    assertTrue(resultCode==0);
+
+    resultCode = TestCaseUtils.applyModifications(true,
+          "dn: cn=schema",
+          "changetype: modify",
+          "add: attributetypes",
+          "attributetypes: ( test-attr-oid NAME 'test-attr-enum' SYNTAX 3.3.3 )",
+          "-",
+          "add: objectclasses",
+          "objectclasses: ( oc-oid NAME 'testOC' SUP top AUXILIARY MUST test-attr-enum)"
+        );
+    assertTrue(resultCode == 0);
+  }
+
+
+
+  //Deletes the enum syntax from the schema.
+  private void deleteEnumSyntax() throws Exception
+  {
+    int resultCode = TestCaseUtils.applyModifications(true,
+      "dn: cn=schema",
+      "changetype: modify",
+      "delete: objectclasses",
+      "objectclasses: ( oc-oid NAME 'testOC' SUP top AUXILIARY MUST test-attr-enum)",
+      "-",
+      "delete: attributetypes",
+      "attributetypes: ( test-attr-oid NAME 'test-attr-enum' SYNTAX 3.3.3 )"
+    );
+
+    assertTrue(resultCode==0);
+
+    resultCode = TestCaseUtils.applyModifications(true,
+    "dn: cn=schema",
+    "changetype: modify",
+    "delete: ldapsyntaxes",
+    "ldapSyntaxes: ( 3.3.3  DESC 'Day Of The Week'  " +
+            "X-ENUM  ( 'monday' 'tuesday'   'wednesday'  'thursday'  'friday'  'saturday' 'sunday') )");
+
+    assertTrue(resultCode==0);
+  }
 }

--
Gitblit v1.10.0