From b8b853dc80f789c90f3159a35f75966034a289aa Mon Sep 17 00:00:00 2001
From: sin <sin@localhost>
Date: Fri, 10 Jul 2009 18:58:37 +0000
Subject: [PATCH] issue 4102: Provide implementation for substitution syntax
---
opends/src/server/org/opends/server/schema/LDAPSyntaxDescriptionSyntax.java | 440 ++++++++++++++++++++++++++++++++++++++++++++++--------
1 files changed, 372 insertions(+), 68 deletions(-)
diff --git a/opends/src/server/org/opends/server/schema/LDAPSyntaxDescriptionSyntax.java b/opends/src/server/org/opends/server/schema/LDAPSyntaxDescriptionSyntax.java
index d36b900..e0a4f74 100644
--- a/opends/src/server/org/opends/server/schema/LDAPSyntaxDescriptionSyntax.java
+++ b/opends/src/server/org/opends/server/schema/LDAPSyntaxDescriptionSyntax.java
@@ -22,10 +22,10 @@
* CDDL HEADER END
*
*
- * Copyright 2006-2008 Sun Microsystems, Inc.
+ * Copyright 2006-2009 Sun Microsystems, Inc.
*/
package org.opends.server.schema;
-import org.opends.messages.Message;
+
@@ -37,7 +37,7 @@
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;
@@ -228,31 +228,18 @@
/**
- * Indicates whether the provided value is acceptable for use in an attribute
- * with this syntax. If it is not, then the reason may be appended to the
- * provided buffer.
- *
- * @param value The value for which to make the determination.
- * @param invalidReason The buffer to which the invalid reason should be
- * appended.
- *
- * @return <CODE>true</CODE> if the provided value is acceptable for use with
- * this syntax, or <CODE>false</CODE> if not.
+ * Parse the OID and Description fields from the ldap syntaxes.
*/
- @Override
- public boolean valueIsAcceptable(ByteSequence value,
- MessageBuilder invalidReason)
+ private static int parseOIDAndDescription(String valueStr,
+ StringBuilder descriptionBuffer, StringBuilder oidBuffer)
+ throws DirectoryException
{
- // Get string representations of the provided value using the provided form
- // and with all lowercase characters.
- String valueStr = value.toString();
- String lowerStr = toLowerCase(valueStr);
-
-
// We'll do this a character at a time. First, skip over any leading
// whitespace.
int pos = 0;
int length = valueStr.length();
+ String lowerStr = toLowerCase(valueStr);
+
while ((pos < length) && (valueStr.charAt(pos) == ' '))
{
pos++;
@@ -263,8 +250,9 @@
// This means that the value was empty or contained only whitespace. That
// is illegal.
- invalidReason.append(ERR_ATTR_SYNTAX_ATTRSYNTAX_EMPTY_VALUE.get());
- return false;
+ Message message = ERR_ATTR_SYNTAX_ATTRSYNTAX_EMPTY_VALUE.get();
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ message);
}
@@ -274,10 +262,11 @@
if (c != '(')
{
- invalidReason.append(
+ Message message =
ERR_ATTR_SYNTAX_ATTRSYNTAX_EXPECTED_OPEN_PARENTHESIS.get(
- valueStr, (pos-1), String.valueOf(c)));
- return false;
+ valueStr, (pos-1), String.valueOf(c));
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ message);
}
@@ -291,27 +280,30 @@
{
// This means that the end of the value was reached before we could find
// the OID. Ths is illegal.
- invalidReason.append(ERR_ATTR_SYNTAX_ATTRSYNTAX_TRUNCATED_VALUE.get(
- valueStr));
- return false;
+ Message message = ERR_ATTR_SYNTAX_ATTRSYNTAX_TRUNCATED_VALUE.get(
+ valueStr);
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ message);
}
-
+ int oidStartPos = pos;
if (isDigit(c))
{
// This must be a numeric OID. In that case, we will accept only digits
// and periods, but not consecutive periods.
boolean lastWasPeriod = false;
- while ((pos < length) && ((c = valueStr.charAt(pos++)) != ' '))
+ while ((pos < length) && ((c = valueStr.charAt(pos)) != ' ')
+ && (c = valueStr.charAt(pos)) != ')')
{
if (c == '.')
{
if (lastWasPeriod)
{
- invalidReason.append(
- ERR_ATTR_SYNTAX_ATTRSYNTAX_DOUBLE_PERIOD_IN_NUMERIC_OID.get(
- valueStr, (pos-1)));
- return false;
+ Message message =
+ ERR_ATTR_SYNTAX_ATTRTYPE_DOUBLE_PERIOD_IN_NUMERIC_OID.
+ get(valueStr, (pos-1));
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ message);
}
else
{
@@ -321,48 +313,56 @@
else if (! isDigit(c))
{
// This must have been an illegal character.
- invalidReason.append(
- ERR_ATTR_SYNTAX_ATTRSYNTAX_ILLEGAL_CHAR_IN_NUMERIC_OID.get(
- valueStr, String.valueOf(c), (pos-1)));
- return false;
+ Message message =
+ ERR_ATTR_SYNTAX_ATTRTYPE_ILLEGAL_CHAR_IN_NUMERIC_OID.
+ get(valueStr, String.valueOf(c), (pos-1));
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ message);
}
else
{
lastWasPeriod = false;
}
+ pos++;
}
}
else
{
// This must be a "fake" OID. In this case, we will only accept
// alphabetic characters, numeric digits, and the hyphen.
- while ((pos < length) && ((c = valueStr.charAt(pos++)) != ' '))
+ while ((pos < length) && ((c = valueStr.charAt(pos)) != ' ')
+ && (c=valueStr.charAt(pos))!=')')
{
if (isAlpha(c) || isDigit(c) || (c == '-') ||
((c == '_') && DirectoryServer.allowAttributeNameExceptions()))
{
// This is fine. It is an acceptable character.
+ pos++;
}
else
{
// This must have been an illegal character.
-
- invalidReason.append(
- ERR_ATTR_SYNTAX_ATTRSYNTAX_ILLEGAL_CHAR_IN_STRING_OID.get(
- valueStr, String.valueOf(c), (pos-1)));
- return false;
+ Message message =
+ ERR_ATTR_SYNTAX_ATTRTYPE_ILLEGAL_CHAR_IN_STRING_OID.
+ get(valueStr, String.valueOf(c), (pos-1));
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ message);
}
}
}
-
// If we're at the end of the value, then it isn't a valid attribute type
// description. Otherwise, parse out the OID.
if (pos >= length)
{
- invalidReason.append(ERR_ATTR_SYNTAX_ATTRSYNTAX_TRUNCATED_VALUE.get(
- valueStr));
- return false;
+ Message message = ERR_ATTR_SYNTAX_ATTRSYNTAX_TRUNCATED_VALUE.get(
+ valueStr);
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ message);
+ }
+ else
+ {
+ oidBuffer.append(lowerStr.substring(oidStartPos, pos));
}
@@ -376,9 +376,10 @@
{
// This means that the end of the value was reached before we could find
// the OID. Ths is illegal.
- invalidReason.append(ERR_ATTR_SYNTAX_ATTRSYNTAX_TRUNCATED_VALUE.get(
- valueStr));
- return false;
+ Message message = ERR_ATTR_SYNTAX_ATTRSYNTAX_TRUNCATED_VALUE.get(
+ valueStr);
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ message);
}
@@ -388,16 +389,15 @@
{
if (pos < length)
{
- invalidReason.append(
+ Message message =
ERR_ATTR_SYNTAX_ATTRSYNTAX_UNEXPECTED_CLOSE_PARENTHESIS.get(
- valueStr, (pos-1)));
- return false;
+ valueStr, (pos-1));
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ message);
}
- return true;
}
-
// The next token must be "DESC" followed by a quoted string.
String tokenName;
try
@@ -413,24 +413,25 @@
TRACER.debugCaught(DebugLogLevel.ERROR, e);
}
- invalidReason.append(
+ Message message =
ERR_ATTR_SYNTAX_ATTRSYNTAX_CANNOT_READ_DESC_TOKEN.get(
- valueStr, pos, getExceptionMessage(e)));
- return false;
+ valueStr, pos, getExceptionMessage(e));
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ message);
}
if (! tokenName.equals("desc"))
{
- invalidReason.append(ERR_ATTR_SYNTAX_ATTRSYNTAX_TOKEN_NOT_DESC.get(
- valueStr, tokenName));
- return false;
+ Message message = ERR_ATTR_SYNTAX_ATTRSYNTAX_TOKEN_NOT_DESC.get(
+ valueStr, tokenName);
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ message);
}
// The next component must be the quoted description.
try
{
- StringBuilder descriptionBuffer = new StringBuilder();
pos = readQuotedString(valueStr, descriptionBuffer, pos);
}
catch (Exception e)
@@ -440,13 +441,173 @@
TRACER.debugCaught(DebugLogLevel.ERROR, e);
}
- invalidReason.append(
+ Message message =
ERR_ATTR_SYNTAX_ATTRSYNTAX_CANNOT_READ_DESC_VALUE.get(
- valueStr, pos, getExceptionMessage(e)));
+ valueStr, pos, getExceptionMessage(e));
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ message);
+ }
+
+ return pos;
+
+ }
+
+
+
+ /**
+ * Decodes the contents of the provided byte sequence as an ldap syntax
+ * definition according to the rules of this syntax. Note that the provided
+ * byte sequence value does not need to be normalized (and in fact, it should
+ * not be in order to allow the desired capitalization to be preserved).
+ *
+ * @param value The byte sequence containing the value
+ * to decode (it does not need to be
+ * normalized).
+ * @param schema The schema to use to resolve references to
+ * other schema elements.
+ * @param allowUnknownElements Indicates whether to allow values that
+ * reference a superior class or required or
+ * optional attribute types which are not
+ * defined in the server schema. This should
+ * only be true when called by
+ * {@code valueIsAcceptable}.
+ *
+ * @return The decoded ldapsyntax definition.
+ *
+ * @throws DirectoryException If the provided value cannot be decoded as an
+ * ldapsyntax definition.
+ */
+ public static LDAPSyntaxDescription decodeLDAPSyntax(ByteSequence value,
+ Schema schema,
+ boolean allowUnknownElements) throws DirectoryException
+ {
+ // Get string representations of the provided value using the provided form
+ // and with all lowercase characters.
+ String valueStr = value.toString();
+ String lowerStr = toLowerCase(valueStr);
+ int length = valueStr.length();
+
+ StringBuilder descriptionBuffer = new StringBuilder();
+ StringBuilder oidBuffer = new StringBuilder();
+
+ //Retrieve the OID and Description part of the defition.
+ int pos = parseOIDAndDescription(valueStr, descriptionBuffer,oidBuffer);
+
+ String oid = oidBuffer.toString();
+ String description = descriptionBuffer.toString();
+ StringBuilder extBuffer = new StringBuilder();
+ //Attribute syntax which will sustitute the syntax with oid.
+ AttributeSyntax subSyntax = null;
+
+ pos = readTokenName(valueStr, extBuffer, pos);
+ String lowerTokenName = toLowerCase(extBuffer.toString());
+
+ if(lowerTokenName.equals("x-subst"))
+ {
+ StringBuilder woidBuffer = new StringBuilder();
+ pos = readQuotedString(lowerStr, woidBuffer, pos);
+ String syntaxOID = woidBuffer.toString();
+ subSyntax = schema.getSyntax(syntaxOID);
+ if(subSyntax == null)
+ {
+ Message message = WARN_ATTR_SYNTAX_ATTRTYPE_UNKNOWN_SYNTAX.get(
+ String.valueOf(oid), syntaxOID);
+ throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION,
+ message);
+ }
+ }
+ else
+ {
+ Message message = WARN_ATTR_SYNTAX_LDAPSYNTAX_UNKNOWN_EXT.get(
+ valueStr,lowerTokenName,pos);
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ message);
+ }
+
+ char c = valueStr.charAt(pos);
+
+ while ((pos < length) && (c == ' '))
+ {
+ 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++)) != ')')
+ {
+
+ Message message =
+ ERR_ATTR_SYNTAX_ATTRSYNTAX_EXPECTED_CLOSE_PARENTHESIS.get(
+ valueStr, pos, String.valueOf(c));
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ message);
+ }
+
+ while (pos < length)
+ {
+ c = valueStr.charAt(pos++);
+ if (c != ' ')
+ {
+
+ Message message =
+ ERR_ATTR_SYNTAX_ATTRSYNTAX_ILLEGAL_CHAR_AFTER_CLOSE.get(
+ valueStr, String.valueOf(c), pos);
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ message);
+ }
+ }
+
+ LDAPSyntaxDescription syntaxDesc = null;
+ //Since we reached here it means everything is OK.
+ if(subSyntax !=null)
+ {
+ //A SubstitutionSyntax is requested.
+ syntaxDesc = new LDAPSyntaxDescription(valueStr,
+ new SubstitutionSyntax(subSyntax,description,oid),
+ description,null);
+ }
+ return syntaxDesc;
+ }
+
+
+
+ /**
+ * Indicates whether the provided value is acceptable for use in an attribute
+ * with this syntax. If it is not, then the reason may be appended to the
+ * provided buffer.
+ *
+ * @param value The value for which to make the determination.
+ * @param invalidReason The buffer to which the invalid reason should be
+ * appended.
+ *
+ * @return <CODE>true</CODE> if the provided value is acceptable for use with
+ * this syntax, or <CODE>false</CODE> if not.
+ */
+ @Override
+ public boolean valueIsAcceptable(ByteSequence value,
+ MessageBuilder invalidReason)
+ {
+ // Get string representations of the provided value using the provided form
+ // and with all lowercase characters.
+ String valueStr = value.toString();
+ StringBuilder descriptionBuffer = new StringBuilder();
+ StringBuilder oidBuffer = new StringBuilder();
+
+ int length = valueStr.length();
+ int pos = 0;
+ try
+ {
+ pos = parseOIDAndDescription(valueStr, descriptionBuffer,oidBuffer);
+ }
+ catch(DirectoryException de)
+ {
+ invalidReason.append(de.getMessageObject());
return false;
}
+
+ char c = valueStr.charAt(pos);
//Check if we have a RFC 4512 style extension.
- if ((c = valueStr.charAt(pos)) != ')')
+ if (c != ')')
{
try {
pos=parseExtension(valueStr, pos);
@@ -724,5 +885,148 @@
{
return false;
}
+
+
+
+ /**
+ * This class provides a substitution mechanism where one unimplemented
+ * syntax can be substituted by another defined syntax. A substitution syntax
+ * is an LDAPSyntaxDescriptionSyntax with X-SUBST extension.
+ */
+ private static class SubstitutionSyntax extends
+ LDAPSyntaxDescriptionSyntax
+ {
+ // The syntax that will subsittute the unimplemented syntax.
+ private AttributeSyntax subSyntax;
+
+ // The description of this syntax.
+ private String description;
+
+ //The oid of this syntax.
+ private String oid;
+
+
+
+ //Creates a new instance of this syntax.
+ private SubstitutionSyntax(AttributeSyntax subSyntax,
+ String description,
+ String oid)
+ {
+ super();
+ this.subSyntax = subSyntax;
+ this.description = description;
+ this.oid = oid;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getSyntaxName()
+ {
+ // There is no name for a substitution syntax.
+ return null;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getOID()
+ {
+ return oid;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getDescription()
+ {
+ return description;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean valueIsAcceptable(ByteSequence value,
+ MessageBuilder invalidReason)
+ {
+ return subSyntax.valueIsAcceptable(value, invalidReason);
+ }
+
+
+
+ /**
+ * 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()
+ {
+ return subSyntax.getEqualityMatchingRule();
+ }
+
+
+
+ /**
+ * 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()
+ {
+ return subSyntax.getOrderingMatchingRule();
+ }
+
+
+
+ /**
+ * 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()
+ {
+ return subSyntax.getSubstringMatchingRule();
+ }
+
+
+
+ /**
+ * 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()
+ {
+ return subSyntax.getApproximateMatchingRule();
+ }
+ }
}
--
Gitblit v1.10.0