mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

sin
15.34.2009 3e15deec52ab7eb4bdd76b51c1c496935987d656
Issue 4116 :Provide implementation for regex syntax
6 files modified
1013 ■■■■■ changed files
opends/src/messages/messages/schema.properties 9 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/backends/SchemaBackend.java 60 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/core/SchemaConfigManager.java 287 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/schema/LDAPSyntaxDescriptionSyntax.java 327 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/types/Schema.java 43 ●●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/schema/LDAPSyntaxTest.java 287 ●●●● patch | view | raw | blame | history
opends/src/messages/messages/schema.properties
@@ -1001,4 +1001,11 @@
MILD_WARN_ATTR_SYNTAX_LDAPSYNTAX_UNKNOWN_EXT_306=The provided value "%s" \
 could not be parsed as an ldap syntax because it contains an unrecognized \
 extension %s at position %d
MILD_WARN_ATTR_SYNTAX_LDAPSYNTAX_REGEX_INVALID_VALUE_307=The provided value \
  "%s" cannot be parsed as a valid regex syntax because it does not match  \
  the pattern "%s"
MILD_WARN_ATTR_SYNTAX_LDAPSYNTAX_REGEX_NO_PATTERN_308=The provided value "%s" \
 could not be parsed as a regex syntax because it does not contain a regex pattern
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
opends/src/server/org/opends/server/backends/SchemaBackend.java
@@ -397,8 +397,9 @@
      LinkedHashSet<String> newDCRs = new LinkedHashSet<String>();
      LinkedHashSet<String> newDSRs = new LinkedHashSet<String>();
      LinkedHashSet<String> newMRUs = new LinkedHashSet<String>();
      LinkedHashSet<String> newLSDs = new LinkedHashSet<String>();
      Schema.genConcatenatedSchema(newATs, newOCs, newNFs, newDCRs, newDSRs,
                                   newMRUs);
                                   newMRUs,newLSDs);
      // Next, generate lists of elements from the previous concatenated schema.
      // If there isn't a previous concatenated schema, then use the base
@@ -449,8 +450,9 @@
      LinkedHashSet<String> oldDCRs = new LinkedHashSet<String>();
      LinkedHashSet<String> oldDSRs = new LinkedHashSet<String>();
      LinkedHashSet<String> oldMRUs = new LinkedHashSet<String>();
      LinkedHashSet<String> oldLSDs = new LinkedHashSet<String>();
      Schema.readConcatenatedSchema(concatFilePath, oldATs, oldOCs, oldNFs,
                                    oldDCRs, oldDSRs, oldMRUs);
                                    oldDCRs, oldDSRs, oldMRUs,oldLSDs);
      // Create a list of modifications and add any differences between the old
      // and new schema into them.
@@ -465,6 +467,8 @@
                                       mods);
      Schema.compareConcatenatedSchema(oldMRUs, newMRUs, matchingRuleUsesType,
                                       mods);
      Schema.compareConcatenatedSchema(oldLSDs, newLSDs, ldapSyntaxesType,
                                      mods);
      if (! mods.isEmpty())
      {
        DirectoryServer.setOfflineSchemaChanges(mods);
@@ -3472,12 +3476,36 @@
    // Start with an empty schema entry.
    Entry schemaEntry = createEmptySchemaEntry();
     /**
     * Add all of the ldap syntax descriptions to the schema entry. We do
     * this only for the real part of the ldapsyntaxes attribute. The real part
     * is read and write to/from the schema files.
     */
    LinkedHashSet<AttributeValue> values = new LinkedHashSet<AttributeValue>();
    for (LDAPSyntaxDescription ldapSyntax :
                                   schema.getLdapSyntaxDescriptions().values())
    {
      if(schemaFile.equals(ldapSyntax.getSchemaFile()))
      {
        values.add(AttributeValues.create(ldapSyntaxesType,
                ldapSyntax.getDefinition()));
      }
    }
   if (! values.isEmpty())
   {
     ArrayList<Attribute> attrList = new ArrayList<Attribute>(1);
     AttributeBuilder builder = new AttributeBuilder(ldapSyntaxesType);
     builder.addAll(values);
     attrList.add(builder.toAttribute());
     schemaEntry.putAttribute(ldapSyntaxesType, attrList);
   }
    // Add all of the appropriate attribute types to the schema entry.  We need
    // to be careful of the ordering to ensure that any superior types in the
    // same file are written before the subordinate types.
    HashSet<AttributeType> addedTypes = new HashSet<AttributeType>();
    LinkedHashSet<AttributeValue> values = new LinkedHashSet<AttributeValue>();
    values = new LinkedHashSet<AttributeValue>();
    for (AttributeType at : schema.getAttributeTypes().values())
    {
      if (schemaFile.equals(at.getSchemaFile()))
@@ -3616,32 +3644,6 @@
    }
    /**
     * Add all of the ldap syntax descriptions to the schema entry. We do
     * this only for the real part of the ldapsyntaxes attribute. The real part
     * is read and write to/from the schema files.
     */
    values = new LinkedHashSet<AttributeValue>();
    for (LDAPSyntaxDescription ldapSyntax :
                                   schema.getLdapSyntaxDescriptions().values())
    {
      if(schemaFile.equals(ldapSyntax.getSchemaFile()))
      {
        values.add(AttributeValues.create(ldapSyntaxesType,
                ldapSyntax.getDefinition()));
      }
    }
   if (! values.isEmpty())
   {
     ArrayList<Attribute> attrList = new ArrayList<Attribute>(1);
     AttributeBuilder builder = new AttributeBuilder(ldapSyntaxesType);
     builder.addAll(values);
     attrList.add(builder.toAttribute());
     schemaEntry.putAttribute(attributeTypesType, attrList);
   }
    if (schemaFile.equals(FILE_USER_SCHEMA_ELEMENTS))
    {
      Map<String, Attribute> attributes = schema.getExtraAttributes();
opends/src/server/org/opends/server/core/SchemaConfigManager.java
@@ -526,6 +526,47 @@
    // Get the attributeTypes attribute from the entry.
    LinkedList<Modification> mods = new LinkedList<Modification>();
    //parse the syntaxes first because attributes rely on these.
    LDAPSyntaxDescriptionSyntax ldapSyntax;
    try
    {
      ldapSyntax = (LDAPSyntaxDescriptionSyntax) schema.getSyntax(
              SYNTAX_LDAP_SYNTAX_OID);
      if (ldapSyntax == null)
      {
        ldapSyntax = new LDAPSyntaxDescriptionSyntax();
        ldapSyntax.initializeSyntax(null);
      }
    }
    catch (Exception e)
    {
      if (debugEnabled())
      {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }
      ldapSyntax = new LDAPSyntaxDescriptionSyntax();
      ldapSyntax.initializeSyntax(null);
    }
    AttributeType ldapSyntaxAttrType =
         schema.getAttributeType(ATTR_LDAP_SYNTAXES_LC);
    if (ldapSyntaxAttrType == null)
    {
      ldapSyntaxAttrType =
           DirectoryServer.getDefaultAttributeType(ATTR_LDAP_SYNTAXES,
                                                   ldapSyntax);
    }
    List<Attribute> ldapSyntaxList = entry.getAttribute(ldapSyntaxAttrType);
    if ((ldapSyntaxList != null) && (! ldapSyntaxList.isEmpty()))
    {
      for (Attribute a : ldapSyntaxList)
      {
        mods.add(new Modification(ModificationType.ADD, a));
      }
    }
    AttributeTypeSyntax attrTypeSyntax;
    try
    {
@@ -773,47 +814,6 @@
      }
    }
    // Get the ldapsyntaxes attribute from the entry.
    LDAPSyntaxDescriptionSyntax ldapSyntax;
    try
    {
      ldapSyntax = (LDAPSyntaxDescriptionSyntax) schema.getSyntax(
              SYNTAX_LDAP_SYNTAX_OID);
      if (ldapSyntax == null)
      {
        ldapSyntax = new LDAPSyntaxDescriptionSyntax();
        ldapSyntax.initializeSyntax(null);
      }
    }
    catch (Exception e)
    {
      if (debugEnabled())
      {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }
      ldapSyntax = new LDAPSyntaxDescriptionSyntax();
      ldapSyntax.initializeSyntax(null);
    }
    AttributeType ldapSyntaxAttrType =
         schema.getAttributeType(ATTR_LDAP_SYNTAXES_LC);
    if (ldapSyntaxAttrType == null)
    {
      ldapSyntaxAttrType =
           DirectoryServer.getDefaultAttributeType(ATTR_LDAP_SYNTAXES,
                                                   ldapSyntax);
    }
    List<Attribute> ldapSyntaxList = entry.getAttribute(ldapSyntaxAttrType);
    if ((ldapSyntaxList != null) && (! ldapSyntaxList.isEmpty()))
    {
      for (Attribute a : ldapSyntaxList)
      {
        mods.add(new Modification(ModificationType.ADD, a));
      }
    }
    // Loop on all the attribute of the schema entry to
    // find the extra attribute that shoule be loaded in the Schema.
    for (Attribute attribute : entry.getAttributes())
@@ -824,6 +824,104 @@
      }
    }
    // Parse the ldapsyntaxes definitions if there are any.
    if (ldapSyntaxList != null)
    {
      for (Attribute a : ldapSyntaxList)
      {
        for (AttributeValue v : a)
        {
          LDAPSyntaxDescription syntaxDescription = null;
          try
          {
            syntaxDescription = LDAPSyntaxDescriptionSyntax.decodeLDAPSyntax(
                    v.getValue(),schema,false);
            syntaxDescription.setExtraProperty(
                    SCHEMA_PROPERTY_FILENAME, (String) null);
            syntaxDescription.setSchemaFile(schemaFile);
          }
          catch (DirectoryException de)
          {
            if (debugEnabled())
            {
              TRACER.debugCaught(DebugLogLevel.ERROR, de);
            }
            Message message = WARN_CONFIG_SCHEMA_CANNOT_PARSE_LDAP_SYNTAX.get(
                    schemaFile,
                    de.getMessageObject());
            if (failOnError)
            {
              throw new ConfigException(message, de);
            }
            else
            {
              logError(message);
              continue;
            }
          }
          catch (Exception e)
          {
            if (debugEnabled())
            {
              TRACER.debugCaught(DebugLogLevel.ERROR, e);
            }
            Message message = WARN_CONFIG_SCHEMA_CANNOT_PARSE_LDAP_SYNTAX.get(
                    schemaFile,
                    v.getValue().toString() + ":  " + getExceptionMessage(e));
            if (failOnError)
            {
              throw new ConfigException(message, e);
            }
            else
            {
              logError(message);
              continue;
            }
          }
           // Register it with the schema.  We will allow duplicates, with the
          // later definition overriding any earlier definition, but we want
          // to trap them and log a warning.
          try
          {
            schema.registerLdapSyntaxDescription(
                                  syntaxDescription, failOnError);
          }
          catch (DirectoryException de)
          {
            if (debugEnabled())
            {
              TRACER.debugCaught(DebugLogLevel.ERROR, de);
            }
            Message message = WARN_CONFIG_SCHEMA_CONFLICTING_LDAP_SYNTAX.get(
                schemaFile, de.getMessageObject());
            logError(message);
            try
            {
              schema.registerLdapSyntaxDescription(syntaxDescription, true);
            }
            catch (Exception e)
            {
              // This should never happen.
              if (debugEnabled())
              {
                TRACER.debugCaught(DebugLogLevel.ERROR, e);
              }
            }
          }
        }
      }
    }
    // Parse the attribute type definitions if there are any.
    if (attrList != null)
    {
@@ -1386,101 +1484,6 @@
      }
    }
    // Parse the ldapsyntaxes definitions if there are any.
    if (ldapSyntaxList != null)
    {
      for (Attribute a : ldapSyntaxList)
      {
        for (AttributeValue v : a)
        {
          LDAPSyntaxDescription syntaxDescription = null;
          try
          {
            syntaxDescription = LDAPSyntaxDescriptionSyntax.decodeLDAPSyntax(
                    v.getValue(),schema,false);
          }
          catch (DirectoryException de)
          {
            if (debugEnabled())
            {
              TRACER.debugCaught(DebugLogLevel.ERROR, de);
            }
            Message message = WARN_CONFIG_SCHEMA_CANNOT_PARSE_LDAP_SYNTAX.get(
                    schemaFile,
                    de.getMessageObject());
            if (failOnError)
            {
              throw new ConfigException(message, de);
            }
            else
            {
              logError(message);
              continue;
            }
          }
          catch (Exception e)
          {
            if (debugEnabled())
            {
              TRACER.debugCaught(DebugLogLevel.ERROR, e);
            }
            Message message = WARN_CONFIG_SCHEMA_CANNOT_PARSE_LDAP_SYNTAX.get(
                    schemaFile,
                    v.getValue().toString() + ":  " + getExceptionMessage(e));
            if (failOnError)
            {
              throw new ConfigException(message, e);
            }
            else
            {
              logError(message);
              continue;
            }
          }
           // Register it with the schema.  We will allow duplicates, with the
          // later definition overriding any earlier definition, but we want
          // to trap them and log a warning.
          try
          {
            schema.registerLdapSyntaxDescription(
                                  syntaxDescription, failOnError);
          }
          catch (DirectoryException de)
          {
            if (debugEnabled())
            {
              TRACER.debugCaught(DebugLogLevel.ERROR, de);
            }
            Message message = WARN_CONFIG_SCHEMA_CONFLICTING_LDAP_SYNTAX.get(
                schemaFile, de.getMessageObject());
            logError(message);
            try
            {
              schema.registerLdapSyntaxDescription(syntaxDescription, true);
            }
            catch (Exception e)
            {
              // This should never happen.
              if (debugEnabled())
              {
                TRACER.debugCaught(DebugLogLevel.ERROR, e);
              }
            }
          }
        }
      }
    }
    return mods;
  }
@@ -1509,12 +1512,12 @@
        attributeOid.equals("1.3.6.1.4.1.1466.101.120.16") ||
        attributeOid.equals("attributetypes-oid")      ||
        attributeOid.equals("objectclasses-oid")       ||
        attributeOid.equals("matchingRules-oid")       ||
        attributeOid.equals("matchingRuleUse-oid")     ||
        attributeOid.equals("NameFormDescription-oid") ||
        attributeOid.equals("dITContentRules-oid")     ||
        attributeOid.equals("dITStructureRules") ||
        attributeOid.equals("ldapSyntaxes-oid")
        attributeOid.equals("matchingrules-oid")       ||
        attributeOid.equals("matchingruleuse-oid")     ||
        attributeOid.equals("nameformdescription-oid") ||
        attributeOid.equals("ditcontentrules-oid")     ||
        attributeOid.equals("ditstructurerules-oid") ||
        attributeOid.equals("ldapsyntaxes-oid")
        )
    {
opends/src/server/org/opends/server/schema/LDAPSyntaxDescriptionSyntax.java
@@ -29,6 +29,8 @@
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;
@@ -496,8 +498,7 @@
    String oid = oidBuffer.toString();
    String description = descriptionBuffer.toString();
    StringBuilder extBuffer = new StringBuilder();
    //Attribute syntax which will sustitute the syntax with oid.
    AttributeSyntax subSyntax = null;
    LDAPSyntaxDescriptionSyntax syntax = null;
    pos = readTokenName(valueStr, extBuffer, pos);
    String lowerTokenName = toLowerCase(extBuffer.toString());
@@ -507,7 +508,7 @@
      StringBuilder woidBuffer = new StringBuilder();
      pos = readQuotedString(lowerStr, woidBuffer, pos);
      String syntaxOID = woidBuffer.toString();
      subSyntax = schema.getSyntax(syntaxOID);
      AttributeSyntax subSyntax = schema.getSyntax(syntaxOID);
      if(subSyntax == null)
      {
        Message message = WARN_ATTR_SYNTAX_ATTRTYPE_UNKNOWN_SYNTAX.get(
@@ -515,6 +516,33 @@
        throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION,
                                     message);
      }
      syntax = new SubstitutionSyntax(subSyntax,description,oid);
    }
    else if(lowerTokenName.equals("x-pattern"))
    {
      StringBuilder regexBuffer = new StringBuilder();
      pos = readQuotedString(valueStr, regexBuffer, pos);
      String regex = regexBuffer.toString();
      if(regex == null)
      {
        Message message = WARN_ATTR_SYNTAX_LDAPSYNTAX_REGEX_NO_PATTERN.get(
               valueStr);
        throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
                message);
      }
      try
      {
        Pattern pattern = Pattern.compile(regex);
        syntax = new RegexSyntax(pattern,description,oid);
      }
      catch(Exception e)
      {
        Message message = WARN_ATTR_SYNTAX_LDAPSYNTAX_REGEX_INVALID_PATTERN.get
                (valueStr,regex);
        throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
                message);
      }
    }
    else
    {
@@ -557,16 +585,8 @@
      }
    }
    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;
    return new LDAPSyntaxDescription(valueStr,syntax,description,null);
  }
@@ -920,7 +940,7 @@
     /**
    /**
     * {@inheritDoc}
     */
     @Override
@@ -966,67 +986,250 @@
      /**
   * 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 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();
    }
  }
  /**
   * 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.
   * This class provides a regex mechanism where a new syntax and its
   * corresponding matching rules can be created on-the-fly. A regex
   * syntax is an LDAPSyntaxDescriptionSyntax with X-PATTERN extension.
   */
  @Override
  public OrderingMatchingRule getOrderingMatchingRule()
  private static class RegexSyntax extends
          LDAPSyntaxDescriptionSyntax
  {
    return subSyntax.getOrderingMatchingRule();
  }
    // The Pattern associated with the regex.
    private Pattern pattern;
    // 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 RegexSyntax(Pattern pattern,
            String description,
            String oid)
    {
      super();
      this.pattern = pattern;
      this.description = description;
      this.oid = oid;
    }
  /**
   * 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();
  }
     /**
     * {@inheritDoc}
     */
     @Override
    public String getSyntaxName()
    {
      // There is no name for a regex syntax.
      return null;
    }
  /**
   * 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();
  }
    /**
     * {@inheritDoc}
     */
     @Override
    public String getOID()
    {
      return oid;
    }
    /**
     * {@inheritDoc}
     */
     @Override
    public String getDescription()
    {
      return description;
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public boolean valueIsAcceptable(ByteSequence value,
                                     MessageBuilder invalidReason)
    {
      String strValue = value.toString();
      boolean matches = pattern.matcher(strValue).matches();
      if(!matches)
      {
        Message message = WARN_ATTR_SYNTAX_LDAPSYNTAX_REGEX_INVALID_VALUE.get(
                strValue,pattern.pattern());
        invalidReason.append(message);
      }
      return matches;
    }
    /**
     * 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 =
                DirectoryServer.getOrderingMatchingRule(OMR_CASE_IGNORE_OID);
      }
      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;
    }
  }
}
opends/src/server/org/opends/server/types/Schema.java
@@ -3386,9 +3386,11 @@
           new LinkedHashSet<String>();
      LinkedHashSet<String> matchingRuleUses =
           new LinkedHashSet<String>();
      LinkedHashSet<String> ldapSyntaxes =
           new LinkedHashSet<String>();
      genConcatenatedSchema(attributeTypes, objectClasses, nameForms,
                            ditContentRules, ditStructureRules,
                            matchingRuleUses);
                            matchingRuleUses,ldapSyntaxes);
      File configFile = new File(DirectoryServer.getConfigFile());
@@ -3459,6 +3461,15 @@
        writer.newLine();
      }
      for (String line : ldapSyntaxes)
      {
        writer.write(ATTR_LDAP_SYNTAXES);
        writer.write(": ");
        writer.write(line);
        writer.newLine();
      }
      writer.close();
      if (concatFile.exists())
@@ -3506,6 +3517,9 @@
   * @param  matchingRuleUses   The set into which to place the
   *                            matching rule uses read from the
   *                            schema files.
   * @param ldapSyntaxes The set into which to place the
   *                            ldap syntaxes read from the
   *                            schema files.
   *
   * @throws  IOException  If a problem occurs while reading the
   *                       schema file elements.
@@ -3516,7 +3530,8 @@
                          LinkedHashSet<String> nameForms,
                          LinkedHashSet<String> ditContentRules,
                          LinkedHashSet<String> ditStructureRules,
                          LinkedHashSet<String> matchingRuleUses)
                          LinkedHashSet<String> matchingRuleUses,
                          LinkedHashSet<String> ldapSyntaxes)
          throws IOException
  {
    // Get a sorted list of the files in the schema directory.
@@ -3641,6 +3656,12 @@
                     ATTR_MATCHING_RULE_USE.length()+1).trim();
          matchingRuleUses.add(value);
        }
        else if(lowerLine.startsWith(ATTR_LDAP_SYNTAXES_LC))
        {
          value = line.substring(
                     ATTR_LDAP_SYNTAXES.length()+1).trim();
          ldapSyntaxes.add(value);
        }
      }
    }
  }
@@ -3671,6 +3692,9 @@
   * @param  matchingRuleUses   The set into which to place the
   *                            matching rule uses read from the
   *                            concatenated schema file.
   * @param ldapSyntaxes The set into which to place the
   *                            ldap syntaxes read from the
   *                            concatenated schema file.
   *
   * @throws  IOException  If a problem occurs while reading the
   *                       schema file elements.
@@ -3681,7 +3705,8 @@
                          LinkedHashSet<String> nameForms,
                          LinkedHashSet<String> ditContentRules,
                          LinkedHashSet<String> ditStructureRules,
                          LinkedHashSet<String> matchingRuleUses)
                          LinkedHashSet<String> matchingRuleUses,
                          LinkedHashSet<String> ldapSyntaxes)
          throws IOException
  {
    BufferedReader reader =
@@ -3730,6 +3755,12 @@
                     ATTR_MATCHING_RULE_USE.length()+1).trim();
        matchingRuleUses.add(value);
      }
      else if (lowerLine.startsWith(ATTR_LDAP_SYNTAXES_LC))
      {
        value = line.substring(
                  ATTR_LDAP_SYNTAXES.length()+1).trim();
        ldapSyntaxes.add(value);
      }
    }
    reader.close();
@@ -3957,6 +3988,12 @@
      extensibleMatchingRules = null;
    }
    if(ldapSyntaxDescriptions != null)
    {
      ldapSyntaxDescriptions.clear();
      ldapSyntaxDescriptions = null;
    }
  }
}
opends/tests/unit-tests-testng/src/server/org/opends/server/schema/LDAPSyntaxTest.java
@@ -32,6 +32,7 @@
import java.util.List;
import org.opends.server.TestCaseUtils;
import org.opends.server.api.AttributeSyntax;
import org.opends.server.core.AddOperation;
import org.opends.server.core.DirectoryServer;
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.protocols.internal.InternalSearchOperation;
@@ -40,6 +41,7 @@
import org.opends.server.types.AttributeValue;
import org.opends.server.types.ByteString;
import org.opends.server.types.DereferencePolicy;
import org.opends.server.types.Entry;
import org.opends.server.types.ResultCode;
import org.opends.server.types.SearchResultEntry;
import org.opends.server.types.SearchScope;
@@ -136,71 +138,70 @@
  /**
   * Tests whether an implemented syntax can't be substituted by another.
   */
   @Test()
   public void testSubstitutionSyntaxForInvalidSubstitution() throws Exception
   {
  @Test()
  public void testSubstitutionSyntaxForInvalidSubstitution() throws Exception
  {
    try
    {
      //Test if we can substitute a directory string syntax by itself.
      int resultCode = TestCaseUtils.applyModifications(true,
        "dn: cn=schema",
        "changetype: modify",
        "add: ldapsyntaxes",
        "ldapsyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.15 " +
        "DESC 'Replacing DirectorySyntax'   " +
        " X-SUBST '1.3.6.1.4.1.1466.115.121.1.15' )");
     try
     {
       //Test if we can substitute a directory string syntax by itself.
        int resultCode = TestCaseUtils.applyModifications(true,
          "dn: cn=schema",
          "changetype: modify",
          "add: ldapsyntaxes",
          "ldapsyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.15 " +
          "DESC 'Replacing DirectorySyntax'   " +
          " X-SUBST '1.3.6.1.4.1.1466.115.121.1.15' )");
      //This is not expected to happen
      assertFalse(resultCode==0);
        //This is not expected to happen
        assertFalse(resultCode==0);
      //Test if we can substitute a directory string syntax by an undefined.
      resultCode = TestCaseUtils.applyModifications(true,
        "dn: cn=schema",
        "changetype: modify",
        "add: ldapsyntaxes",
        "ldapsyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.15 " +
        "DESC 'Replacing DirectorySyntax'   " +
        " X-SUBST '1.1.1' )");
        //Test if we can substitute a directory string syntax by an undefined.
        resultCode = TestCaseUtils.applyModifications(true,
          "dn: cn=schema",
          "changetype: modify",
          "add: ldapsyntaxes",
          "ldapsyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.15 " +
          "DESC 'Replacing DirectorySyntax'   " +
          " X-SUBST '1.1.1' )");
        //This is not expected to happen
        assertFalse(resultCode==0);
      //This is not expected to happen
      assertFalse(resultCode==0);
        //Test if we can substitute a core syntax with a user-defined
        //syntax
        addSubtitutionSyntax();
        //Replace the IA5Stringsyntax with the custom syntax we just created.
         resultCode = TestCaseUtils.applyModifications(true,
          "dn: cn=schema",
          "changetype: modify",
          "add: ldapsyntaxes",
          "ldapsyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.26 " +
          "DESC 'Replacing DirectorySyntax'   " +
          " X-SUBST '9.9.9' )");
      //Test if we can substitute a core syntax with a user-defined
      //syntax
      addSubtitutionSyntax();
      //Replace the IA5Stringsyntax with the custom syntax we just created.
      resultCode = TestCaseUtils.applyModifications(true,
        "dn: cn=schema",
        "changetype: modify",
        "add: ldapsyntaxes",
        "ldapsyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.26 " +
        "DESC 'Replacing DirectorySyntax'   " +
        " X-SUBST '9.9.9' )");
        //This is not expected to happen
        assertFalse(resultCode==0);
     }
     finally
     {
      //This is not expected to happen
      assertFalse(resultCode==0);
    }
    finally
    {
      deleteSubstitutionSyntax();
     }
   }
    }
  }
   /**
  /**
    * Tests whether both the virtual and the newly added real substitution
    * sytanx are available when a search is made for ldapsyntaxes attribute.
    *
    * @throws java.lang.Exception
    */
   @Test()
   public void testSubstitutionSyntaxSearch() throws Exception
   {
     try
     {
  @Test()
  public void testSubstitutionSyntaxSearch() throws Exception
  {
    try
    {
      addSubtitutionSyntax();
      InternalClientConnection conn =
      InternalClientConnection.getRootConnection();
@@ -230,9 +231,9 @@
      assertNotNull(e);
      Attribute attr = e.getAttribute("ldapsyntaxes").get(0);
      Iterator<AttributeValue> iter = attr.iterator();
      //There are other ways of doing it but we will extract the OID
      //from the attribute values and then check to see if our
      //from the attribute values and then check to see if our
      //OID is found in the result set or not.
      List<String> syntaxList = new ArrayList<String>();
      while(iter.hasNext())
@@ -241,21 +242,21 @@
        //parse the OIDs.
        syntaxList.add(getOIDFromLdapSyntax(val.toString()));
      }
      assertTrue(syntaxList.size() ==
              DirectoryServer.getAttributeSyntaxSet().size() ) ;
      //Check if we find our OID.
      //Check if we find our OID.
      assertTrue(syntaxList.contains("9.9.9"));
      //DirectoryString.
      assertTrue(syntaxList.contains("1.3.6.1.4.1.1466.115.121.1.15"));
      //IA5String.
      assertTrue(syntaxList.contains("1.3.6.1.4.1.1466.115.121.1.26"));
     }
     finally
     {
       deleteSubstitutionSyntax();
     }
   }
    }
    finally
    {
      deleteSubstitutionSyntax();
    }
  }
@@ -265,6 +266,7 @@
    *
    * @throws java.lang.Exception
    */
   @Test()
   public void testSubsitutionSyntaxAddValues() throws Exception
   {
     try
@@ -298,6 +300,109 @@
   }
  /**
    * Tests whether it is possible to add values after a regex syntax
    * has been added.
    *
    * @throws java.lang.Exception
    */
  @Test()
  public void testRegexSyntaxAddValues() throws Exception
  {
    try
    {
      addRegexSyntax();
      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-regex: invalid regex");
      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-regex: host:0.0.0");
    }
    finally
    {
     deleteRegexSyntax();
    }
  }
  /**
   * Tests the search using regex syntax.
   *
   * @throws java.lang.Exception
   */
  @Test()
  public void testRegexSyntaxSearch() throws Exception
  {
    try
    {
      addRegexSyntax();
      //This addition should go through.
      TestCaseUtils.addEntry(
        "dn: cn=test,o=test",
        "objectclass: person",
        "objectclass: testOC",
        "cn: test",
        "sn: xyz",
        "test-attr-regex: host:0.0.0");
      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-regex=host:0.0.0"),
                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
    {
      deleteRegexSyntax();
    }
  }
  //Parses the OID from the syntax defitions.
  private String getOIDFromLdapSyntax(String valueStr)
  {
@@ -319,18 +424,9 @@
    }
    int oidStartPos = pos;
    boolean lastWasPeriod = false;
    while ((pos < length) && ((c = valueStr.charAt(pos)) != ' ')
          && (c = valueStr.charAt(pos)) != ')')
    {
      if (c == '.')
      {
        lastWasPeriod = true;
      }
      else
      {
        lastWasPeriod = false;
      }
      pos++;
    }
    return valueStr.substring(oidStartPos, pos);
@@ -366,4 +462,57 @@
    assertTrue(resultCode==0);
  }
   //Adds a regex syntax to the schema.
  private void addRegexSyntax() throws Exception
  {
    //Add the substitution syntax for an unimplemented syntax.
    int resultCode = TestCaseUtils.applyModifications(true,
    "dn: cn=schema",
    "changetype: modify",
    "add: ldapsyntaxes",
    "ldapSyntaxes: ( 1.1.1 DESC 'Host and Port in the format of HOST:PORT'  " +
            "X-PATTERN '^[a-z-A-Z]+:[0-9.]+\\d$' )");
    assertTrue(resultCode==0);
    resultCode = TestCaseUtils.applyModifications(true,
          "dn: cn=schema",
          "changetype: modify",
          "add: attributetypes",
          "attributetypes: ( test-attr-oid NAME 'test-attr-regex' SYNTAX 1.1.1 )",
          "-",
          "add: objectclasses",
          "objectclasses: ( oc-oid NAME 'testOC' SUP top AUXILIARY MUST test-attr-regex)"
        );
    assertTrue(resultCode == 0);
  }
  //Deletes the regex syntax from the schema.
  private void deleteRegexSyntax() throws Exception
  {
    //delete the substitution syntax.
    int resultCode = TestCaseUtils.applyModifications(true,
      "dn: cn=schema",
      "changetype: modify",
      "delete: objectclasses",
      "objectclasses: ( oc-oid NAME 'testOC' SUP top AUXILIARY MUST test-attr-regex)",
      "-",
      "delete: attributetypes",
      "attributetypes: ( test-attr-oid NAME 'test-attr-regex' SYNTAX 1.1.1 )"
    );
    assertTrue(resultCode==0);
    resultCode = TestCaseUtils.applyModifications(true,
    "dn: cn=schema",
    "changetype: modify",
    "delete: ldapsyntaxes",
    "ldapSyntaxes: ( 1.1.1 DESC 'Host and Port in the format of HOST:PORT'  " +
            "X-PATTERN '^[a-z-A-Z]+:[0-9.]+\\d$' )");
    assertTrue(resultCode==0);
  }
}