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/schema/LDAPSyntaxDescriptionSyntax.java | 448 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 433 insertions(+), 15 deletions(-)
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());
+ }
+ }
+ }
}
--
Gitblit v1.10.0