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

neil_a_wilson
09.20.2007 bdf67a3c15262fb750ae1c0302212dc03ff94a06
opendj-sdk/opends/resource/schema/00-core.ldif
@@ -21,7 +21,7 @@
# CDDL HEADER END
#
#
#      Portions Copyright 2006 Sun Microsystems, Inc.
#      Portions Copyright 2006-2007 Sun Microsystems, Inc.
#
#
# This file contains a core set of attribute type and objectlass definitions
@@ -172,20 +172,16 @@
  EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12
  SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation
  X-ORIGIN 'RFC 2252' )
attributeTypes: ( 2.5.21.5 NAME 'attributeTypes'
  EQUALITY objectIdentifierFirstComponentMatch
attributeTypes: ( 2.5.21.5 NAME 'attributeTypes' EQUALITY caseIgnoreMatch
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.3 USAGE directoryOperation
  X-ORIGIN 'RFC 2252' )
attributeTypes: ( 2.5.21.6 NAME 'objectClasses'
  EQUALITY objectIdentifierFirstComponentMatch
attributeTypes: ( 2.5.21.6 NAME 'objectClasses' EQUALITY caseIgnoreMatch
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.37 USAGE directoryOperation
  X-ORIGIN 'RFC 2252' )
attributeTypes: ( 2.5.21.4 NAME 'matchingRules'
  EQUALITY objectIdentifierFirstComponentMatch
attributeTypes: ( 2.5.21.4 NAME 'matchingRules' EQUALITY caseIgnoreMatch
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.30 USAGE directoryOperation
  X-ORIGIN 'RFC 2252' )
attributeTypes: ( 2.5.21.8 NAME 'matchingRuleUse'
  EQUALITY objectIdentifierFirstComponentMatch
attributeTypes: ( 2.5.21.8 NAME 'matchingRuleUse' EQUALITY caseIgnoreMatch
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.31 USAGE directoryOperation
  X-ORIGIN 'RFC 2252' )
attributeTypes: ( 1.3.6.1.4.1.1466.101.120.5 NAME 'namingContexts'
@@ -206,15 +202,13 @@
attributeTypes: ( 1.3.6.1.4.1.1466.101.120.16 NAME 'ldapSyntaxes'
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.54 USAGE directoryOperation
  X-ORIGIN 'RFC 2252' )
attributeTypes: ( 2.5.21.1 NAME 'dITStructureRules'
  EQUALITY integerFirstComponentMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.17
  USAGE directoryOperation X-ORIGIN 'RFC 2252' )
attributeTypes: ( 2.5.21.7 NAME 'nameForms'
  EQUALITY objectIdentifierFirstComponentMatch
attributeTypes: ( 2.5.21.1 NAME 'dITStructureRules' EQUALITY caseIgnoreMatch
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.17 USAGE directoryOperation
  X-ORIGIN 'RFC 2252' )
attributeTypes: ( 2.5.21.7 NAME 'nameForms' EQUALITY caseIgnoreMatch
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.35 USAGE directoryOperation
  X-ORIGIN 'RFC 2252' )
attributeTypes: ( 2.5.21.2 NAME 'dITContentRules'
  EQUALITY objectIdentifierFirstComponentMatch
attributeTypes: ( 2.5.21.2 NAME 'dITContentRules' EQUALITY caseIgnoreMatch
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.16 USAGE directoryOperation
  X-ORIGIN 'RFC 2252' )
attributeTypes: ( 0.9.2342.19200300.100.1.25 NAME 'dc'
@@ -464,7 +458,7 @@
  AUXILIARY X-ORIGIN 'RFC 2252' )
objectClasses: ( 2.5.20.1 NAME 'subschema' AUXILIARY MAY ( dITStructureRules $
  nameForms $ ditContentRules $ objectClasses $ attributeTypes $ matchingRules $
  matchingRuleUse ) X-ORIGIn 'RFC 2252' )
  matchingRuleUse ) X-ORIGIN 'RFC 2252' )
objectClasses: ( 0.9.2342.19200300.100.4.5 NAME 'account' SUP top STRUCTURAL
  MUST uid MAY ( description $ seeAlso $ l $ o $ ou $ host )
  X-ORIGIN 'RFC 4524' )
opendj-sdk/opends/src/server/org/opends/server/backends/SchemaBackend.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2006 Sun Microsystems, Inc.
 *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
 */
package org.opends.server.backends;
@@ -32,6 +32,7 @@
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.security.MessageDigest;
import java.util.ArrayList;
@@ -43,6 +44,8 @@
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.zip.Deflater;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
@@ -52,8 +55,10 @@
import javax.crypto.CipherOutputStream;
import javax.crypto.Mac;
import org.opends.server.api.AlertGenerator;
import org.opends.server.api.Backend;
import org.opends.server.api.ConfigurableComponent;
import org.opends.server.api.MatchingRule;
import org.opends.server.config.BooleanConfigAttribute;
import org.opends.server.config.ConfigAttribute;
import org.opends.server.config.ConfigEntry;
@@ -67,6 +72,10 @@
import org.opends.server.core.SchemaConfigManager;
import org.opends.server.core.SearchOperation;
import org.opends.server.schema.AttributeTypeSyntax;
import org.opends.server.schema.DITContentRuleSyntax;
import org.opends.server.schema.DITStructureRuleSyntax;
import org.opends.server.schema.MatchingRuleUseSyntax;
import org.opends.server.schema.NameFormSyntax;
import org.opends.server.schema.ObjectClassSyntax;
import org.opends.server.types.Attribute;
import org.opends.server.types.AttributeType;
@@ -77,6 +86,8 @@
import org.opends.server.types.ConfigChangeResult;
import org.opends.server.types.CryptoManager;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.DITContentRule;
import org.opends.server.types.DITStructureRule;
import org.opends.server.types.DN;
import org.opends.server.types.Entry;
import org.opends.server.types.ErrorLogCategory;
@@ -85,16 +96,21 @@
import org.opends.server.types.InitializationException;
import org.opends.server.types.LDIFImportConfig;
import org.opends.server.types.LDIFExportConfig;
import org.opends.server.types.MatchingRuleUse;
import org.opends.server.types.Modification;
import org.opends.server.types.ModificationType;
import org.opends.server.types.NameForm;
import org.opends.server.types.ObjectClass;
import org.opends.server.types.ObjectClassType;
import org.opends.server.types.RDN;
import org.opends.server.types.RestoreConfig;
import org.opends.server.types.ResultCode;
import org.opends.server.types.Schema;
import org.opends.server.types.SchemaFileElement;
import org.opends.server.types.SearchFilter;
import org.opends.server.types.SearchScope;
import org.opends.server.util.DynamicConstants;
import org.opends.server.util.LDIFReader;
import org.opends.server.util.LDIFException;
import org.opends.server.util.LDIFWriter;
import static org.opends.server.config.ConfigConstants.*;
@@ -114,7 +130,7 @@
 */
public class SchemaBackend
       extends Backend
       implements ConfigurableComponent
       implements ConfigurableComponent, AlertGenerator
{
  /**
   * The fully-qualified name of this class for debugging purposes.
@@ -844,7 +860,8 @@
    // elements, nor will we allow modification of any other attributes.  Make
    // sure that the included modify operation is acceptable within these
    // constraints.
    List<Modification> mods = modifyOperation.getModifications();
    ArrayList<Modification> mods =
         new ArrayList<Modification>(modifyOperation.getModifications());
    if (mods.isEmpty())
    {
      // There aren't any modifications, so we don't need to do anything.
@@ -852,11 +869,15 @@
    }
    Schema newSchema = DirectoryServer.getSchema().duplicate();
    LinkedList<AttributeType> newAttrTypes = new LinkedList<AttributeType>();
    LinkedList<ObjectClass> newObjectClasses = new LinkedList<ObjectClass>();
    TreeSet<String> modifiedSchemaFiles = new TreeSet<String>();
    LinkedHashSet<SchemaFileElement> dependentElements =
         new LinkedHashSet<SchemaFileElement>();
    int pos = -1;
    for (Modification m : mods)
    {
      pos++;
      if (m.isInternal())
      {
        // We don't need to do anything for internal modifications (e.g., like
@@ -864,301 +885,2026 @@
        continue;
      }
      // Determine the type of modification to perform.  We will support add and
      // delete operations in the schema, and we will also support the ability
      // to add a schema element that already exists and treat it as a
      // replacement of that existing element.
      Attribute     a  = m.getAttribute();
      AttributeType at = a.getAttributeType();
      switch (m.getModificationType())
      {
        case ADD:
          // This is fine, as long as there aren't any conflicts later.
          LinkedHashSet<AttributeValue> values = a.getValues();
          if (values.isEmpty())
          {
            continue;
          }
          if (at.equals(attributeTypesType))
          {
            for (AttributeValue v : values)
            {
              AttributeType type;
              try
              {
                type = AttributeTypeSyntax.decodeAttributeType(v.getValue(),
                                                               newSchema);
              }
              catch (DirectoryException de)
              {
                assert debugException(CLASS_NAME, "replaceEntry", de);
                int msgID = MSGID_SCHEMA_MODIFY_CANNOT_DECODE_ATTRTYPE;
                String message = getMessage(msgID, v.getStringValue(),
                                            de.getErrorMessage());
                throw new DirectoryException(
                               ResultCode.INVALID_ATTRIBUTE_SYNTAX, message,
                               msgID, de);
              }
              addAttributeType(type, newSchema, modifiedSchemaFiles);
            }
          }
          else if (at.equals(objectClassesType))
          {
            for (AttributeValue v : values)
            {
              ObjectClass oc;
              try
              {
                oc = ObjectClassSyntax.decodeObjectClass(v.getValue(),
                                                         newSchema);
              }
              catch (DirectoryException de)
              {
                assert debugException(CLASS_NAME, "replaceEntry", de);
                int msgID = MSGID_SCHEMA_MODIFY_CANNOT_DECODE_OBJECTCLASS;
                String message = getMessage(msgID, v.getStringValue(),
                                            de.getErrorMessage());
                throw new DirectoryException(
                               ResultCode.INVALID_ATTRIBUTE_SYNTAX, message,
                               msgID, de);
              }
              addObjectClass(oc, newSchema, modifiedSchemaFiles);
            }
          }
          else if (at.equals(nameFormsType))
          {
            for (AttributeValue v : values)
            {
              NameForm nf;
              try
              {
                nf = NameFormSyntax.decodeNameForm(v.getValue(), newSchema);
              }
              catch (DirectoryException de)
              {
                assert debugException(CLASS_NAME, "replaceEntry", de);
                int msgID = MSGID_SCHEMA_MODIFY_CANNOT_DECODE_NAME_FORM;
                String message = getMessage(msgID, v.getStringValue(),
                                            de.getErrorMessage());
                throw new DirectoryException(
                               ResultCode.INVALID_ATTRIBUTE_SYNTAX, message,
                               msgID, de);
              }
              addNameForm(nf, newSchema, modifiedSchemaFiles);
            }
          }
          else if (at.equals(ditContentRulesType))
          {
            for (AttributeValue v : values)
            {
              DITContentRule dcr;
              try
              {
                dcr = DITContentRuleSyntax.decodeDITContentRule(v.getValue(),
                                                                newSchema);
              }
              catch (DirectoryException de)
              {
                assert debugException(CLASS_NAME, "replaceEntry", de);
                int msgID = MSGID_SCHEMA_MODIFY_CANNOT_DECODE_DCR;
                String message = getMessage(msgID, v.getStringValue(),
                                            de.getErrorMessage());
                throw new DirectoryException(
                               ResultCode.INVALID_ATTRIBUTE_SYNTAX, message,
                               msgID, de);
              }
              addDITContentRule(dcr, newSchema, modifiedSchemaFiles);
            }
          }
          else if (at.equals(ditStructureRulesType))
          {
            for (AttributeValue v : values)
            {
              DITStructureRule dsr;
              try
              {
                dsr = DITStructureRuleSyntax.decodeDITStructureRule(
                           v.getValue(), newSchema, false);
              }
              catch (DirectoryException de)
              {
                assert debugException(CLASS_NAME, "replaceEntry", de);
                int msgID = MSGID_SCHEMA_MODIFY_CANNOT_DECODE_DSR;
                String message = getMessage(msgID, v.getStringValue(),
                                            de.getErrorMessage());
                throw new DirectoryException(
                               ResultCode.INVALID_ATTRIBUTE_SYNTAX, message,
                               msgID, de);
              }
              addDITStructureRule(dsr, newSchema, modifiedSchemaFiles);
            }
          }
          else if (at.equals(matchingRuleUsesType))
          {
            for (AttributeValue v : values)
            {
              MatchingRuleUse mru;
              try
              {
                mru = MatchingRuleUseSyntax.decodeMatchingRuleUse(v.getValue(),
                                                                  newSchema);
              }
              catch (DirectoryException de)
              {
                assert debugException(CLASS_NAME, "replaceEntry", de);
                int msgID = MSGID_SCHEMA_MODIFY_CANNOT_DECODE_MR_USE;
                String message = getMessage(msgID, v.getStringValue(),
                                            de.getErrorMessage());
                throw new DirectoryException(
                               ResultCode.INVALID_ATTRIBUTE_SYNTAX, message,
                               msgID, de);
              }
              addMatchingRuleUse(mru, newSchema, modifiedSchemaFiles);
            }
          }
          else
          {
            int    msgID   = MSGID_SCHEMA_MODIFY_UNSUPPORTED_ATTRIBUTE_TYPE;
            String message = getMessage(msgID, a.getName());
            throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM,
                                         message, msgID);
          }
          break;
        case DELETE:
          // FIXME -- We need to support this.
          int    msgID   = MSGID_SCHEMA_DELETE_MODTYPE_NOT_SUPPORTED;
          String message = getMessage(msgID);
          throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message,
                                       msgID);
          values = a.getValues();
          if (values.isEmpty())
          {
            int    msgID   = MSGID_SCHEMA_MODIFY_DELETE_NO_VALUES;
            String message = getMessage(msgID, a.getName());
            throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM,
                                         message, msgID);
          }
        case REPLACE:
          // FIXME -- Should we support this?
        case INCREMENT:
          if (at.equals(attributeTypesType))
          {
            for (AttributeValue v : values)
            {
              AttributeType type;
              try
              {
                type = AttributeTypeSyntax.decodeAttributeType(v.getValue(),
                                                               newSchema);
              }
              catch (DirectoryException de)
              {
                assert debugException(CLASS_NAME, "replaceEntry", de);
                int msgID = MSGID_SCHEMA_MODIFY_CANNOT_DECODE_ATTRTYPE;
                String message = getMessage(msgID, v.getStringValue(),
                                            de.getErrorMessage());
                throw new DirectoryException(
                               ResultCode.INVALID_ATTRIBUTE_SYNTAX, message,
                               msgID, de);
              }
              removeAttributeType(type, newSchema, mods, pos,
                                  modifiedSchemaFiles);
            }
          }
          else if (at.equals(objectClassesType))
          {
            for (AttributeValue v : values)
            {
              ObjectClass oc;
              try
              {
                oc = ObjectClassSyntax.decodeObjectClass(v.getValue(),
                                                         newSchema);
              }
              catch (DirectoryException de)
              {
                assert debugException(CLASS_NAME, "replaceEntry", de);
                int msgID = MSGID_SCHEMA_MODIFY_CANNOT_DECODE_OBJECTCLASS;
                String message = getMessage(msgID, v.getStringValue(),
                                            de.getErrorMessage());
                throw new DirectoryException(
                               ResultCode.INVALID_ATTRIBUTE_SYNTAX, message,
                               msgID, de);
              }
              removeObjectClass(oc, newSchema, mods, pos, modifiedSchemaFiles);
            }
          }
          else if (at.equals(nameFormsType))
          {
            for (AttributeValue v : values)
            {
              NameForm nf;
              try
              {
                nf = NameFormSyntax.decodeNameForm(v.getValue(), newSchema);
              }
              catch (DirectoryException de)
              {
                assert debugException(CLASS_NAME, "replaceEntry", de);
                int msgID = MSGID_SCHEMA_MODIFY_CANNOT_DECODE_NAME_FORM;
                String message = getMessage(msgID, v.getStringValue(),
                                            de.getErrorMessage());
                throw new DirectoryException(
                               ResultCode.INVALID_ATTRIBUTE_SYNTAX, message,
                               msgID, de);
              }
              removeNameForm(nf, newSchema, mods, pos, modifiedSchemaFiles);
            }
          }
          else if (at.equals(ditContentRulesType))
          {
            for (AttributeValue v : values)
            {
              DITContentRule dcr;
              try
              {
                dcr = DITContentRuleSyntax.decodeDITContentRule(v.getValue(),
                                                                newSchema);
              }
              catch (DirectoryException de)
              {
                assert debugException(CLASS_NAME, "replaceEntry", de);
                int msgID = MSGID_SCHEMA_MODIFY_CANNOT_DECODE_DCR;
                String message = getMessage(msgID, v.getStringValue(),
                                            de.getErrorMessage());
                throw new DirectoryException(
                               ResultCode.INVALID_ATTRIBUTE_SYNTAX, message,
                               msgID, de);
              }
              removeDITContentRule(dcr, newSchema, mods, pos,
                                   modifiedSchemaFiles);
            }
          }
          else if (at.equals(ditStructureRulesType))
          {
            for (AttributeValue v : values)
            {
              DITStructureRule dsr;
              try
              {
                dsr = DITStructureRuleSyntax.decodeDITStructureRule(
                           v.getValue(), newSchema, false);
              }
              catch (DirectoryException de)
              {
                assert debugException(CLASS_NAME, "replaceEntry", de);
                int msgID = MSGID_SCHEMA_MODIFY_CANNOT_DECODE_DSR;
                String message = getMessage(msgID, v.getStringValue(),
                                            de.getErrorMessage());
                throw new DirectoryException(
                               ResultCode.INVALID_ATTRIBUTE_SYNTAX, message,
                               msgID, de);
              }
              removeDITStructureRule(dsr, newSchema, mods, pos,
                                     modifiedSchemaFiles);
            }
          }
          else if (at.equals(matchingRuleUsesType))
          {
            for (AttributeValue v : values)
            {
              MatchingRuleUse mru;
              try
              {
                mru = MatchingRuleUseSyntax.decodeMatchingRuleUse(v.getValue(),
                                                                  newSchema);
              }
              catch (DirectoryException de)
              {
                assert debugException(CLASS_NAME, "replaceEntry", de);
                int msgID = MSGID_SCHEMA_MODIFY_CANNOT_DECODE_MR_USE;
                String message = getMessage(msgID, v.getStringValue(),
                                            de.getErrorMessage());
                throw new DirectoryException(
                               ResultCode.INVALID_ATTRIBUTE_SYNTAX, message,
                               msgID, de);
              }
              removeMatchingRuleUse(mru, newSchema, mods, pos,
                                    modifiedSchemaFiles);
            }
          }
          else
          {
            int    msgID   = MSGID_SCHEMA_MODIFY_UNSUPPORTED_ATTRIBUTE_TYPE;
            String message = getMessage(msgID, a.getName());
            throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM,
                                         message, msgID);
          }
          break;
        default:
          // FIXME -- Make sure to update this message once we support
          // schema deletes and possibly replace.
          msgID   = MSGID_SCHEMA_INVALID_MODIFICATION_TYPE;
          message = getMessage(msgID, m.getModificationType());
          int    msgID   = MSGID_SCHEMA_INVALID_MODIFICATION_TYPE;
          String message = getMessage(msgID, m.getModificationType());
          throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message,
                                       msgID);
      }
      // At the present time, we will only allow modification of the
      // attributeTypes and objectClasses attributes.
      Attribute     a = m.getAttribute();
      AttributeType t = a.getAttributeType();
      if (t.equals(attributeTypesType))
      {
        for (AttributeValue v : a.getValues())
        {
          AttributeType newType;
          try
          {
            newType = AttributeTypeSyntax.decodeAttributeType(v.getValue(),
                                                              newSchema);
          }
          catch (DirectoryException de)
          {
            assert debugException(CLASS_NAME, "replaceEntry", de);
            int    msgID   = MSGID_SCHEMA_MODIFY_CANNOT_DECODE_ATTRTYPE;
            String message = getMessage(msgID, v.getStringValue(),
                                        de.getErrorMessage());
            throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
                                         message, msgID, de);
          }
          try
          {
            newSchema.registerAttributeType(newType, false);
            newAttrTypes.add(newType);
          }
          catch (DirectoryException de)
          {
            assert debugException(CLASS_NAME, "replaceEntry", de);
            int    msgID   = MSGID_SCHEMA_MODIFY_ATTRTYPE_ALREADY_EXISTS;
            String message = getMessage(msgID, newType.getNameOrOID(),
                                        de.getErrorMessage());
            throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM,
                                         message, msgID, de);
          }
        }
      }
      else if (t.equals(objectClassesType))
      {
        for (AttributeValue v : a.getValues())
        {
          ObjectClass newClass;
          try
          {
            newClass = ObjectClassSyntax.decodeObjectClass(v.getValue(),
                                                           newSchema);
          }
          catch (DirectoryException de)
          {
            assert debugException(CLASS_NAME, "replaceEntry", de);
            int    msgID   = MSGID_SCHEMA_MODIFY_CANNOT_DECODE_OBJECTCLASS;
            String message = getMessage(msgID, v.getStringValue(),
                                        de.getErrorMessage());
            throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
                                         message, msgID, de);
          }
          // If there is a superior class, then make sure it is defined.
          ObjectClass superiorClass = newClass.getSuperiorClass();
          if (superiorClass != null)
          {
            String lowerName = toLowerCase(superiorClass.getNameOrOID());
            if (! newSchema.hasObjectClass(lowerName))
            {
              int msgID = MSGID_SCHEMA_MODIFY_UNDEFINED_SUPERIOR_OBJECTCLASS;
              String message = getMessage(msgID, newClass.getNameOrOID(),
                                          superiorClass.getNameOrOID());
              throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM,
                                           message, msgID);
            }
          }
          // Make sure that all the associated attribute types are defined.
          for (AttributeType at : newClass.getRequiredAttributes())
          {
            String lowerName = toLowerCase(at.getNameOrOID());
            if (! newSchema.hasAttributeType(lowerName))
            {
              int    msgID   = MSGID_SCHEMA_MODIFY_OC_UNDEFINED_REQUIRED_ATTR;
              String message = getMessage(msgID, newClass.getNameOrOID(),
                                          at.getNameOrOID());
              throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM,
                                           message, msgID);
            }
          }
          for (AttributeType at : newClass.getOptionalAttributes())
          {
            String lowerName = toLowerCase(at.getNameOrOID());
            if (! newSchema.hasAttributeType(lowerName))
            {
              int    msgID   = MSGID_SCHEMA_MODIFY_OC_UNDEFINED_OPTIONAL_ATTR;
              String message = getMessage(msgID, newClass.getNameOrOID(),
                                          at.getNameOrOID());
              throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM,
                                           message, msgID);
            }
          }
          try
          {
            newSchema.registerObjectClass(newClass, false);
            newObjectClasses.add(newClass);
          }
          catch (DirectoryException de)
          {
            assert debugException(CLASS_NAME, "replaceEntry", de);
            int    msgID   = MSGID_SCHEMA_MODIFY_OBJECTCLASS_ALREADY_EXISTS;
            String message = getMessage(msgID, newClass.getNameOrOID(),
                                        de.getErrorMessage());
            throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM,
                                         message, msgID, de);
          }
        }
      }
      else
      {
        int    msgID   = MSGID_SCHEMA_MODIFY_UNSUPPORTED_ATTRIBUTE_TYPE;
        String message = getMessage(msgID, a.getName());
        throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message,
                                     msgID);
      }
    }
    // If we've gotten here, then everything looks OK.  Add the new schema
    // elements to the 99-user.ldif file and swing the new schema into place.
    String schemaDirPath = SchemaConfigManager.getSchemaDirectoryPath();
    File userSchemaFile = new File(schemaDirPath, FILE_USER_SCHEMA_ELEMENTS);
    Entry userSchemaEntry = null;
    if (userSchemaFile.exists())
    {
      // There's already a set of user-defined schema elements, so we'll need to
      // add these new elements to that set.
      LDIFReader ldifReader = null;
      try
      {
        LDIFImportConfig importConfig =
             new LDIFImportConfig(userSchemaFile.getAbsolutePath());
        ldifReader = new LDIFReader(importConfig);
        userSchemaEntry = ldifReader.readEntry(true);
      }
      catch (Exception e)
      {
        assert debugException(CLASS_NAME, "replaceEntry", e);
        int    msgID   = MSGID_SCHEMA_MODIFY_CANNOT_READ_EXISTING_USER_SCHEMA;
        String message = getMessage(msgID, userSchemaFile.getAbsolutePath(),
                                    stackTraceToSingleLineString(e));
        throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
                                     message, msgID, e);
      }
      finally
      {
        if (ldifReader != null)
        {
          ldifReader.close();
        }
      }
    }
    if (userSchemaEntry == null)
    {
      // This could happen if there was no user schema file or if it was there
      // but didn't have any entries.  At any rate, create a new, empty entry.
      userSchemaEntry = createEmptySchemaEntry();
    }
    // Add all of the new schema elements to the entry.
    if (! newAttrTypes.isEmpty())
    {
      LinkedHashSet<AttributeValue> values =
           new LinkedHashSet<AttributeValue>();
      for (AttributeType t : newAttrTypes)
      {
        StringBuilder buffer = new StringBuilder();
        t.toString(buffer, false);
        values.add(new AttributeValue(attributeTypesType, buffer.toString()));
      }
      Attribute attrTypeAttribute = new Attribute(attributeTypesType,
                                                  ATTR_ATTRIBUTE_TYPES, values);
      LinkedList<AttributeValue> duplicateValues =
           new LinkedList<AttributeValue>();
      userSchemaEntry.addAttribute(attrTypeAttribute, duplicateValues);
    }
    if (! newObjectClasses.isEmpty())
    {
      LinkedHashSet<AttributeValue> values =
           new LinkedHashSet<AttributeValue>();
      for (ObjectClass oc : newObjectClasses)
      {
        StringBuilder buffer = new StringBuilder();
        oc.toString(buffer, false);
        values.add(new AttributeValue(attributeTypesType, buffer.toString()));
      }
      Attribute ocAttribute = new Attribute(objectClassesType,
                                            ATTR_OBJECTCLASSES, values);
      LinkedList<AttributeValue> duplicateValues =
           new LinkedList<AttributeValue>();
      userSchemaEntry.addAttribute(ocAttribute, duplicateValues);
    }
    // Swing the new schema into place.
    // If we've gotten here, then everything looks OK.  We'll re-write all
    // impacted schema files by first creating them in a temporary location
    // and then replacing the existing schema files with the new versions.
    // If all that goes successfully, then activate the new schema.
    HashMap<String,File> tempSchemaFiles = new HashMap<String,File>();
    try
    {
      File tempSchemaFile = new File(userSchemaFile.getAbsolutePath() + ".tmp");
      LDIFExportConfig exportConfig =
           new LDIFExportConfig(tempSchemaFile.getAbsolutePath(),
                                ExistingFileBehavior.OVERWRITE);
      LDIFWriter writer = null;
      try
      for (String schemaFile : modifiedSchemaFiles)
      {
        writer = new LDIFWriter(exportConfig);
        writer.writeEntry(userSchemaEntry);
      }
      finally
      {
        if (writer != null)
        {
          writer.close();
        }
        File tempSchemaFile = writeTempSchemaFile(newSchema, schemaFile);
        tempSchemaFiles.put(schemaFile, tempSchemaFile);
      }
      File oldSchemaFile = null;
      if (userSchemaFile.exists())
      {
        oldSchemaFile = new File(userSchemaFile.getAbsolutePath() + ".old");
        if (oldSchemaFile.exists())
        {
          oldSchemaFile.delete();
        }
        userSchemaFile.renameTo(oldSchemaFile);
      }
      tempSchemaFile.renameTo(userSchemaFile);
      if (oldSchemaFile != null)
      {
        oldSchemaFile.delete();
      }
      installSchemaFiles(tempSchemaFiles);
      DirectoryServer.setSchema(newSchema);
    }
    catch (DirectoryException de)
    {
      assert debugException(CLASS_NAME, "replaceEntry", de);
      throw de;
    }
    catch (Exception e)
    {
      assert debugException(CLASS_NAME, "replaceEntry", e);
      int    msgID   = MSGID_SCHEMA_MODIFY_CANNOT_WRITE_NEW_SCHEMA;
      String message = getMessage(msgID, userSchemaFile.getAbsolutePath(),
                                  stackTraceToSingleLineString(e));
      String message = getMessage(msgID, stackTraceToSingleLineString(e));
      throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
                                   message, msgID, e);
    }
    finally
    {
      cleanUpTempSchemaFiles(tempSchemaFiles);
    }
  }
  /**
   * Handles all processing required for adding the provided attribute type to
   * the given schema, replacing an existing type if necessary, and ensuring all
   * other metadata is properly updated.
   *
   * @param  attributeType        The attribute type to add or replace in the
   *                              server schema.
   * @param  schema               The schema to which the attribute type should
   *                              be added.
   * @param  modifiedSchemaFiles  The names of the schema files containing
   *                              schema elements that have been updated as part
   *                              of the schema modification.
   *
   * @throws  DirectoryException  If a problem occurs while attempting to add
   *                              the provided attribute type to the server
   *                              schema.
   */
  private void addAttributeType(AttributeType attributeType, Schema schema,
                                Set<String> modifiedSchemaFiles)
          throws DirectoryException
  {
    assert debugEnter(CLASS_NAME, "addAttributeType",
                      String.valueOf(attributeType), String.valueOf(schema),
                      String.valueOf(modifiedSchemaFiles));
    // First, see if the specified attribute type already exists.  We'll check
    // the OID and all of the names, which means that it's possible there could
    // be more than one match (although if there is, then we'll refuse the
    // operation).
    AttributeType existingType =
         schema.getAttributeType(attributeType.getOID());
    for (String name : attributeType.getNormalizedNames())
    {
      AttributeType t = schema.getAttributeType(name);
      if (t == null)
      {
        continue;
      }
      else if (existingType == null)
      {
        existingType = t;
      }
      else if (existingType != t)
      {
        // NOTE:  We really do want to use "!=" instead of "! t.equals()"
        // because we want to check whether it's the same object instance, not
        // just a logical equivalent.
        int msgID = MSGID_SCHEMA_MODIFY_MULTIPLE_CONFLICTS_FOR_ADD_ATTRTYPE;
        String message = getMessage(msgID, attributeType.getNameOrOID(),
                                    existingType.getNameOrOID(),
                                    t.getNameOrOID());
        throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message,
                                     msgID);
      }
    }
    // Make sure that the new attribute type doesn't reference an undefined
    // superior attribute type.
    AttributeType superiorType = attributeType.getSuperiorType();
    if (superiorType != null)
    {
      if (! schema.hasAttributeType(superiorType.getOID()))
      {
        int    msgID   = MSGID_SCHEMA_MODIFY_UNDEFINED_SUPERIOR_ATTRIBUTE_TYPE;
        String message = getMessage(msgID, attributeType.getNameOrOID(),
                                    superiorType.getNameOrOID());
        throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message,
                                     msgID);
      }
    }
    // If there is no existing type, then we're adding a new attribute.
    // Otherwise, we're replacing an existing one.
    if (existingType == null)
    {
      schema.registerAttributeType(attributeType, false);
      String schemaFile = attributeType.getSchemaFile();
      if ((schemaFile == null) || (schemaFile.length() == 0))
      {
        schemaFile = FILE_USER_SCHEMA_ELEMENTS;
        attributeType.setSchemaFile(schemaFile);
      }
      modifiedSchemaFiles.add(schemaFile);
    }
    else
    {
      schema.deregisterAttributeType(existingType);
      schema.registerAttributeType(attributeType, false);
      schema.rebuildDependentElements(existingType);
      if ((attributeType.getSchemaFile() == null) ||
          (attributeType.getSchemaFile().length() == 0))
      {
        String schemaFile = existingType.getSchemaFile();
        if ((schemaFile == null) || (schemaFile.length() == 0))
        {
          schemaFile = FILE_USER_SCHEMA_ELEMENTS;
        }
        attributeType.setSchemaFile(schemaFile);
        modifiedSchemaFiles.add(schemaFile);
      }
      else
      {
        String newSchemaFile = attributeType.getSchemaFile();
        String oldSchemaFile = existingType.getSchemaFile();
        if ((oldSchemaFile == null) || oldSchemaFile.equals(newSchemaFile))
        {
          modifiedSchemaFiles.add(newSchemaFile);
        }
        else
        {
          modifiedSchemaFiles.add(newSchemaFile);
          modifiedSchemaFiles.add(oldSchemaFile);
        }
      }
    }
  }
  /**
   * Handles all processing required to remove the provided attribute type from
   * the server schema, ensuring all other metadata is properly updated.  Note
   * that this method will first check to see whether the same attribute type
   * will be later added to the server schema with an updated definition, and if
   * so then the removal will be ignored because the later add will be handled
   * as a replace.  If the attribute type will not be replaced with a new
   * definition, then this method will ensure that there are no other schema
   * elements that depend on the attribute type before allowing it to be
   * removed.
   *
   * @param  attributeType        The attribute type to remove from the server
   *                              schema.
   * @param  schema               The schema from which the attribute type
   *                              should be removed.
   * @param  modifications        The full set of modifications to be processed
   *                              against the server schema.
   * @param  currentPosition      The position of the modification currently
   *                              being performed.
   * @param  modifiedSchemaFiles  The names of the schema files containing
   *                              schema elements that have been updated as part
   *                              of the schema modification.
   *
   * @throws  DirectoryException  If a problem occurs while attempting to remove
   *                              the provided attribute type from the server
   *                              schema.
   */
  private void removeAttributeType(AttributeType attributeType, Schema schema,
                                   ArrayList<Modification> modifications,
                                   int currentPosition,
                                   Set<String> modifiedSchemaFiles)
          throws DirectoryException
  {
    assert debugEnter(CLASS_NAME, "removeAttributeType",
                      String.valueOf(attributeType), String.valueOf(schema),
                      String.valueOf(modifications),
                      String.valueOf(currentPosition),
                      String.valueOf(modifiedSchemaFiles));
    // See if the specified attribute type is actually defined in the server
    // schema.  If not, then fail.
    AttributeType removeType = schema.getAttributeType(attributeType.getOID());
    if ((removeType == null) || (! removeType.equals(attributeType)))
    {
      int    msgID   = MSGID_SCHEMA_MODIFY_REMOVE_NO_SUCH_ATTRIBUTE_TYPE;
      String message = getMessage(msgID, attributeType.getNameOrOID());
      throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message,
                                   msgID);
    }
    // See if there is another modification later to add the attribute type back
    // into the schema.  If so, then it's a replace and we should ignore the
    // remove because adding it back will handle the replace.
    for (int i=currentPosition+1; i < modifications.size(); i++)
    {
      Modification m = modifications.get(i);
      Attribute    a = m.getAttribute();
      if ((m.getModificationType() != ModificationType.ADD) ||
          (! a.getAttributeType().equals(attributeTypesType)))
      {
        continue;
      }
      for (AttributeValue v : a.getValues())
      {
        AttributeType at;
        try
        {
          at = AttributeTypeSyntax.decodeAttributeType(v.getValue(), schema);
        }
        catch (DirectoryException de)
        {
          assert debugException(CLASS_NAME, "removeAttributeType", de);
          int msgID = MSGID_SCHEMA_MODIFY_CANNOT_DECODE_ATTRTYPE;
          String message = getMessage(msgID, v.getStringValue(),
                                      de.getErrorMessage());
          throw new DirectoryException(
                         ResultCode.INVALID_ATTRIBUTE_SYNTAX, message,
                         msgID, de);
        }
        if (attributeType.getOID().equals(at.getOID()))
        {
          // We found a match where the attribute type is added back later, so
          // we don't need to do anything else here.
          return;
        }
      }
    }
    // Make sure that the attribute type isn't used as the superior type for
    // any other attributes.
    for (AttributeType at : schema.getAttributeTypes().values())
    {
      AttributeType superiorType = at.getSuperiorType();
      if ((superiorType != null) && superiorType.equals(removeType))
      {
        int    msgID   = MSGID_SCHEMA_MODIFY_REMOVE_AT_SUPERIOR_TYPE;
        String message = getMessage(msgID, removeType.getNameOrOID(),
                                    superiorType.getNameOrOID());
        throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message,
                                     msgID);
      }
    }
    // Make sure that the attribute type isn't used as a required or optional
    // attribute type in any objectclass.
    for (ObjectClass oc : schema.getObjectClasses().values())
    {
      if (oc.getRequiredAttributes().contains(removeType) ||
          oc.getOptionalAttributes().contains(removeType))
      {
        int    msgID   = MSGID_SCHEMA_MODIFY_REMOVE_AT_IN_OC;
        String message = getMessage(msgID, removeType.getNameOrOID(),
                                    oc.getNameOrOID());
        throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message,
                                     msgID);
      }
    }
    // Make sure that the attribute type isn't used as a required or optional
    // attribute type in any name form.
    for (NameForm nf : schema.getNameFormsByObjectClass().values())
    {
      if (nf.getRequiredAttributes().contains(removeType) ||
          nf.getOptionalAttributes().contains(removeType))
      {
        int    msgID   = MSGID_SCHEMA_MODIFY_REMOVE_AT_IN_NF;
        String message = getMessage(msgID, removeType.getNameOrOID(),
                                    nf.getNameOrOID());
        throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message,
                                     msgID);
      }
    }
    // Make sure that the attribute type isn't used as a required, optional, or
    // prohibited attribute type in any DIT content rule.
    for (DITContentRule dcr : schema.getDITContentRules().values())
    {
      if (dcr.getRequiredAttributes().contains(removeType) ||
          dcr.getOptionalAttributes().contains(removeType) ||
          dcr.getProhibitedAttributes().contains(removeType))
      {
        int    msgID   = MSGID_SCHEMA_MODIFY_REMOVE_AT_IN_DCR;
        String message = getMessage(msgID, removeType.getNameOrOID(),
                                    dcr.getName());
        throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message,
                                     msgID);
      }
    }
    // Make sure that the attribute type isn't referenced by any matching rule
    // use.
    for (MatchingRuleUse mru : schema.getMatchingRuleUses().values())
    {
      if (mru.getAttributes().contains(removeType))
      {
        int    msgID   = MSGID_SCHEMA_MODIFY_REMOVE_AT_IN_MR_USE;
        String message = getMessage(msgID, removeType.getNameOrOID(),
                                    mru.getName());
        throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message,
                                     msgID);
      }
    }
    // If we've gotten here, then it's OK to remove the attribute type from
    // the schema.
    schema.deregisterAttributeType(removeType);
    String schemaFile = removeType.getSchemaFile();
    if (schemaFile != null)
    {
      modifiedSchemaFiles.add(schemaFile);
    }
  }
  /**
   * Handles all processing required for adding the provided objectclass to the
   * given schema, replacing an existing class if necessary, and ensuring
   * all other metadata is properly updated.
   *
   * @param  objectClass          The objectclass to add or replace in the
   *                              server schema.
   * @param  schema               The schema to which the objectclass should be
   *                              added.
   * @param  modifiedSchemaFiles  The names of the schema files containing
   *                              schema elements that have been updated as part
   *                              of the schema modification.
   *
   * @throws  DirectoryException  If a problem occurs while attempting to add
   *                              the provided objectclass to the server schema.
   */
  private void addObjectClass(ObjectClass objectClass, Schema schema,
                              Set<String> modifiedSchemaFiles)
          throws DirectoryException
  {
    assert debugEnter(CLASS_NAME, "addObjectClass", String.valueOf(objectClass),
                      String.valueOf(schema),
                      String.valueOf(modifiedSchemaFiles));
    // First, see if the specified objectclass already exists.  We'll check the
    // OID and all of the names, which means that it's possible there could be
    // more than one match (although if there is, then we'll refuse the
    // operation).
    ObjectClass existingClass =
         schema.getObjectClass(objectClass.getOID());
    for (String name : objectClass.getNormalizedNames())
    {
      ObjectClass oc = schema.getObjectClass(name);
      if (oc == null)
      {
        continue;
      }
      else if (existingClass == null)
      {
        existingClass = oc;
      }
      else if (existingClass != oc)
      {
        // NOTE:  We really do want to use "!=" instead of "! t.equals()"
        // because we want to check whether it's the same object instance, not
        // just a logical equivalent.
        int msgID = MSGID_SCHEMA_MODIFY_MULTIPLE_CONFLICTS_FOR_ADD_OBJECTCLASS;
        String message = getMessage(msgID, objectClass.getNameOrOID(),
                                    existingClass.getNameOrOID(),
                                    oc.getNameOrOID());
        throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message,
                                     msgID);
      }
    }
    // Make sure that the new objectclass doesn't reference an undefined
    // superior class, or an undefined required or optional attribute type.
    ObjectClass superiorClass = objectClass.getSuperiorClass();
    if (superiorClass != null)
    {
      if (! schema.hasObjectClass(superiorClass.getOID()))
      {
        int    msgID   = MSGID_SCHEMA_MODIFY_UNDEFINED_SUPERIOR_OBJECTCLASS;
        String message = getMessage(msgID, objectClass.getNameOrOID(),
                                    superiorClass.getNameOrOID());
        throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message,
                                     msgID);
      }
    }
    for (AttributeType at : objectClass.getRequiredAttributes())
    {
      if (! schema.hasAttributeType(at.getOID()))
      {
        int    msgID   = MSGID_SCHEMA_MODIFY_OC_UNDEFINED_REQUIRED_ATTR;
        String message = getMessage(msgID, objectClass.getNameOrOID(),
                                    at.getNameOrOID());
        throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message,
                                     msgID);
      }
    }
    for (AttributeType at : objectClass.getOptionalAttributes())
    {
      if (! schema.hasAttributeType(at.getOID()))
      {
        int    msgID   = MSGID_SCHEMA_MODIFY_OC_UNDEFINED_OPTIONAL_ATTR;
        String message = getMessage(msgID, objectClass.getNameOrOID(),
                                    at.getNameOrOID());
        throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message,
                                     msgID);
      }
    }
    // If there is no existing class, then we're adding a new objectclass.
    // Otherwise, we're replacing an existing one.
    if (existingClass == null)
    {
      schema.registerObjectClass(objectClass, false);
      String schemaFile = objectClass.getSchemaFile();
      if ((schemaFile == null) || (schemaFile.length() == 0))
      {
        schemaFile = FILE_USER_SCHEMA_ELEMENTS;
        objectClass.setSchemaFile(schemaFile);
      }
      modifiedSchemaFiles.add(schemaFile);
    }
    else
    {
      schema.deregisterObjectClass(existingClass);
      schema.registerObjectClass(objectClass, false);
      schema.rebuildDependentElements(existingClass);
      if ((objectClass.getSchemaFile() == null) ||
          (objectClass.getSchemaFile().length() == 0))
      {
        String schemaFile = existingClass.getSchemaFile();
        if ((schemaFile == null) || (schemaFile.length() == 0))
        {
          schemaFile = FILE_USER_SCHEMA_ELEMENTS;
        }
        objectClass.setSchemaFile(schemaFile);
        modifiedSchemaFiles.add(schemaFile);
      }
      else
      {
        String newSchemaFile = objectClass.getSchemaFile();
        String oldSchemaFile = existingClass.getSchemaFile();
        if ((oldSchemaFile == null) || oldSchemaFile.equals(newSchemaFile))
        {
          modifiedSchemaFiles.add(newSchemaFile);
        }
        else
        {
          modifiedSchemaFiles.add(newSchemaFile);
          modifiedSchemaFiles.add(oldSchemaFile);
        }
      }
    }
  }
  /**
   * Handles all processing required to remove the provided objectclass from the
   * server schema, ensuring all other metadata is properly updated.  Note that
   * this method will first check to see whether the same objectclass will be
   * later added to the server schema with an updated definition, and if so then
   * the removal will be ignored because the later add will be handled as a
   * replace.  If the objectclass will not be replaced with a new definition,
   * then this method will ensure that there are no other schema elements that
   * depend on the objectclass before allowing it to be removed.
   *
   * @param  objectClass          The objectclass to remove from the server
   *                              schema.
   * @param  schema               The schema from which the objectclass should
   *                              be removed.
   * @param  modifications        The full set of modifications to be processed
   *                              against the server schema.
   * @param  currentPosition      The position of the modification currently
   *                              being performed.
   * @param  modifiedSchemaFiles  The names of the schema files containing
   *                              schema elements that have been updated as part
   *                              of the schema modification.
   *
   * @throws  DirectoryException  If a problem occurs while attempting to remove
   *                              the provided objectclass from the server
   *                              schema.
   */
  private void removeObjectClass(ObjectClass objectClass, Schema schema,
                                 ArrayList<Modification> modifications,
                                 int currentPosition,
                                 Set<String> modifiedSchemaFiles)
          throws DirectoryException
  {
    assert debugEnter(CLASS_NAME, "removeObjectClass",
                      String.valueOf(objectClass), String.valueOf(schema),
                      String.valueOf(modifications),
                      String.valueOf(currentPosition),
                      String.valueOf(modifiedSchemaFiles));
    // See if the specified objectclass is actually defined in the server
    // schema.  If not, then fail.
    ObjectClass removeClass = schema.getObjectClass(objectClass.getOID());
    if ((removeClass == null) || (! removeClass.equals(objectClass)))
    {
      int    msgID   = MSGID_SCHEMA_MODIFY_REMOVE_NO_SUCH_OBJECTCLASS;
      String message = getMessage(msgID, objectClass.getNameOrOID());
      throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message,
                                   msgID);
    }
    // See if there is another modification later to add the objectclass back
    // into the schema.  If so, then it's a replace and we should ignore the
    // remove because adding it back will handle the replace.
    for (int i=currentPosition+1; i < modifications.size(); i++)
    {
      Modification m = modifications.get(i);
      Attribute    a = m.getAttribute();
      if ((m.getModificationType() != ModificationType.ADD) ||
          (! a.getAttributeType().equals(objectClassesType)))
      {
        continue;
      }
      for (AttributeValue v : a.getValues())
      {
        ObjectClass oc;
        try
        {
          oc = ObjectClassSyntax.decodeObjectClass(v.getValue(), schema);
        }
        catch (DirectoryException de)
        {
          assert debugException(CLASS_NAME, "removeObjectClass", de);
          int msgID = MSGID_SCHEMA_MODIFY_CANNOT_DECODE_OBJECTCLASS;
          String message = getMessage(msgID, v.getStringValue(),
                                      de.getErrorMessage());
          throw new DirectoryException(
                         ResultCode.INVALID_ATTRIBUTE_SYNTAX, message,
                         msgID, de);
        }
        if (objectClass.getOID().equals(oc.getOID()))
        {
          // We found a match where the objectClass is added back later, so we
          // don't need to do anything else here.
          return;
        }
      }
    }
    // Make sure that the objectclass isn't used as the superior class for any
    // other objectclass.
    for (ObjectClass oc : schema.getObjectClasses().values())
    {
      ObjectClass superiorClass = oc.getSuperiorClass();
      if ((superiorClass != null) && superiorClass.equals(removeClass))
      {
        int    msgID   = MSGID_SCHEMA_MODIFY_REMOVE_OC_SUPERIOR_CLASS;
        String message = getMessage(msgID, removeClass.getNameOrOID(),
                                    superiorClass.getNameOrOID());
        throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message,
                                     msgID);
      }
    }
    // Make sure that the objectclass isn't used as the structural class for
    // any name form.
    NameForm nf = schema.getNameForm(removeClass);
    if (nf != null)
    {
      int    msgID   = MSGID_SCHEMA_MODIFY_REMOVE_OC_IN_NF;
      String message = getMessage(msgID, removeClass.getNameOrOID(),
                                  nf.getNameOrOID());
      throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message,
                                   msgID);
    }
    // Make sure that the objectclass isn't used as a structural or auxiliary
    // class for any DIT content rule.
    for (DITContentRule dcr : schema.getDITContentRules().values())
    {
      if (dcr.getStructuralClass().equals(removeClass) ||
          dcr.getAuxiliaryClasses().contains(removeClass))
      {
        int    msgID   = MSGID_SCHEMA_MODIFY_REMOVE_OC_IN_DCR;
        String message = getMessage(msgID, removeClass.getNameOrOID(),
                                    dcr.getName());
        throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message,
                                     msgID);
      }
    }
    // If we've gotten here, then it's OK to remove the objectclass from the
    // schema.
    schema.deregisterObjectClass(removeClass);
    String schemaFile = removeClass.getSchemaFile();
    if (schemaFile != null)
    {
      modifiedSchemaFiles.add(schemaFile);
    }
  }
  /**
   * Handles all processing required for adding the provided name form to the
   * the given schema, replacing an existing name form if necessary, and
   * ensuring all other metadata is properly updated.
   *
   * @param  nameForm             The name form to add or replace in the server
   *                              schema.
   * @param  schema               The schema to which the name form should be
   *                              added.
   * @param  modifiedSchemaFiles  The names of the schema files containing
   *                              schema elements that have been updated as part
   *                              of the schema modification.
   *
   * @throws  DirectoryException  If a problem occurs while attempting to add
   *                              the provided name form to the server schema.
   */
  private void addNameForm(NameForm nameForm, Schema schema,
                           Set<String> modifiedSchemaFiles)
          throws DirectoryException
  {
    assert debugEnter(CLASS_NAME, "addNameForm", String.valueOf(nameForm),
                      String.valueOf(schema),
                      String.valueOf(modifiedSchemaFiles));
    // First, see if the specified name form already exists.  We'll check the
    // OID and all of the names, which means that it's possible there could be
    // more than one match (although if there is, then we'll refuse the
    // operation).
    NameForm existingNF =
         schema.getNameForm(nameForm.getOID());
    for (String name : nameForm.getNames().keySet())
    {
      NameForm nf = schema.getNameForm(name);
      if (nf == null)
      {
        continue;
      }
      else if (existingNF == null)
      {
        existingNF = nf;
      }
      else if (existingNF != nf)
      {
        // NOTE:  We really do want to use "!=" instead of "! t.equals()"
        // because we want to check whether it's the same object instance, not
        // just a logical equivalent.
        int msgID = MSGID_SCHEMA_MODIFY_MULTIPLE_CONFLICTS_FOR_ADD_NAME_FORM;
        String message = getMessage(msgID, nameForm.getNameOrOID(),
                                    existingNF.getNameOrOID(),
                                    nf.getNameOrOID());
        throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message,
                                     msgID);
      }
    }
    // Make sure that the new name form doesn't reference an undefined
    // structural class, or an undefined required or optional attribute type.
    ObjectClass structuralClass = nameForm.getStructuralClass();
    if (! schema.hasObjectClass(structuralClass.getOID()))
    {
      int    msgID   = MSGID_SCHEMA_MODIFY_NF_UNDEFINED_STRUCTURAL_OC;
      String message = getMessage(msgID, nameForm.getNameOrOID(),
                                  structuralClass.getNameOrOID());
      throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message,
                                   msgID);
    }
    if (structuralClass.getObjectClassType() != ObjectClassType.STRUCTURAL)
    {
      int    msgID   = MSGID_SCHEMA_MODIFY_NF_OC_NOT_STRUCTURAL;
      String message = getMessage(msgID, nameForm.getNameOrOID(),
                                  structuralClass.getNameOrOID());
      throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message,
                                   msgID);
    }
    NameForm existingNFForClass = schema.getNameForm(structuralClass);
    if ((existingNFForClass != null) && (existingNFForClass != existingNF))
    {
      int    msgID   = MSGID_SCHEMA_MODIFY_STRUCTURAL_OC_CONFLICT_FOR_ADD_NF;
      String message = getMessage(msgID, nameForm.getNameOrOID(),
                                  structuralClass.getNameOrOID(),
                                  existingNFForClass.getNameOrOID());
      throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message,
                                   msgID);
    }
    for (AttributeType at : nameForm.getRequiredAttributes())
    {
      if (! schema.hasAttributeType(at.getOID()))
      {
        int    msgID   = MSGID_SCHEMA_MODIFY_NF_UNDEFINED_REQUIRED_ATTR;
        String message = getMessage(msgID, nameForm.getNameOrOID(),
                                    at.getNameOrOID());
        throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message,
                                     msgID);
      }
    }
    for (AttributeType at : nameForm.getOptionalAttributes())
    {
      if (! schema.hasAttributeType(at.getOID()))
      {
        int    msgID   = MSGID_SCHEMA_MODIFY_NF_UNDEFINED_OPTIONAL_ATTR;
        String message = getMessage(msgID, nameForm.getNameOrOID(),
                                    at.getNameOrOID());
        throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message,
                                     msgID);
      }
    }
    // If there is no existing class, then we're adding a new name form.
    // Otherwise, we're replacing an existing one.
    if (existingNF == null)
    {
      schema.registerNameForm(nameForm, false);
      String schemaFile = nameForm.getSchemaFile();
      if ((schemaFile == null) || (schemaFile.length() == 0))
      {
        schemaFile = FILE_USER_SCHEMA_ELEMENTS;
        nameForm.setSchemaFile(schemaFile);
      }
      modifiedSchemaFiles.add(schemaFile);
    }
    else
    {
      schema.deregisterNameForm(existingNF);
      schema.registerNameForm(nameForm, false);
      schema.rebuildDependentElements(existingNF);
      if ((nameForm.getSchemaFile() == null) ||
          (nameForm.getSchemaFile().length() == 0))
      {
        String schemaFile = existingNF.getSchemaFile();
        if ((schemaFile == null) || (schemaFile.length() == 0))
        {
          schemaFile = FILE_USER_SCHEMA_ELEMENTS;
        }
        nameForm.setSchemaFile(schemaFile);
        modifiedSchemaFiles.add(schemaFile);
      }
      else
      {
        String newSchemaFile = nameForm.getSchemaFile();
        String oldSchemaFile = existingNF.getSchemaFile();
        if ((oldSchemaFile == null) || oldSchemaFile.equals(newSchemaFile))
        {
          modifiedSchemaFiles.add(newSchemaFile);
        }
        else
        {
          modifiedSchemaFiles.add(newSchemaFile);
          modifiedSchemaFiles.add(oldSchemaFile);
        }
      }
    }
  }
  /**
   * Handles all processing required to remove the provided name form from the
   * server schema, ensuring all other metadata is properly updated.  Note that
   * this method will first check to see whether the same name form will be
   * later added to the server schema with an updated definition, and if so then
   * the removal will be ignored because the later add will be handled as a
   * replace.  If the name form will not be replaced with a new definition, then
   * this method will ensure that there are no other schema elements that depend
   * on the name form before allowing it to be removed.
   *
   * @param  nameForm             The name form to remove from the server
   *                              schema.
   * @param  schema               The schema from which the name form should be
   *                              be removed.
   * @param  modifications        The full set of modifications to be processed
   *                              against the server schema.
   * @param  currentPosition      The position of the modification currently
   *                              being performed.
   * @param  modifiedSchemaFiles  The names of the schema files containing
   *                              schema elements that have been updated as part
   *                              of the schema modification.
   *
   * @throws  DirectoryException  If a problem occurs while attempting to remove
   *                              the provided name form from the server schema.
   */
  private void removeNameForm(NameForm nameForm, Schema schema,
                              ArrayList<Modification> modifications,
                              int currentPosition,
                              Set<String> modifiedSchemaFiles)
          throws DirectoryException
  {
    assert debugEnter(CLASS_NAME, "removeNameForm",
                      String.valueOf(nameForm), String.valueOf(schema),
                      String.valueOf(modifications),
                      String.valueOf(currentPosition),
                      String.valueOf(modifiedSchemaFiles));
    // See if the specified name form is actually defined in the server schema.
    // If not, then fail.
    NameForm removeNF = schema.getNameForm(nameForm.getOID());
    if ((removeNF == null) || (! removeNF.equals(nameForm)))
    {
      int    msgID   = MSGID_SCHEMA_MODIFY_REMOVE_NO_SUCH_NAME_FORM;
      String message = getMessage(msgID, nameForm.getNameOrOID());
      throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message,
                                   msgID);
    }
    // See if there is another modification later to add the name form back
    // into the schema.  If so, then it's a replace and we should ignore the
    // remove because adding it back will handle the replace.
    for (int i=currentPosition+1; i < modifications.size(); i++)
    {
      Modification m = modifications.get(i);
      Attribute    a = m.getAttribute();
      if ((m.getModificationType() != ModificationType.ADD) ||
          (! a.getAttributeType().equals(nameFormsType)))
      {
        continue;
      }
      for (AttributeValue v : a.getValues())
      {
        NameForm nf;
        try
        {
          nf = NameFormSyntax.decodeNameForm(v.getValue(), schema);
        }
        catch (DirectoryException de)
        {
          assert debugException(CLASS_NAME, "removeNameForm", de);
          int msgID = MSGID_SCHEMA_MODIFY_CANNOT_DECODE_NAME_FORM;
          String message = getMessage(msgID, v.getStringValue(),
                                      de.getErrorMessage());
          throw new DirectoryException(
                         ResultCode.INVALID_ATTRIBUTE_SYNTAX, message,
                         msgID, de);
        }
        if (nameForm.getOID().equals(nf.getOID()))
        {
          // We found a match where the name form is added back later, so we
          // don't need to do anything else here.
          return;
        }
      }
    }
    // Make sure that the name form isn't referenced by any DIT structure
    // rule.
    DITStructureRule dsr = schema.getDITStructureRule(removeNF);
    if (dsr != null)
    {
      int    msgID   = MSGID_SCHEMA_MODIFY_REMOVE_NF_IN_DSR;
      String message = getMessage(msgID, removeNF.getNameOrOID(),
                                  dsr.getNameOrRuleID());
      throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message,
                                   msgID);
    }
    // If we've gotten here, then it's OK to remove the name form from the
    // schema.
    schema.deregisterNameForm(removeNF);
    String schemaFile = removeNF.getSchemaFile();
    if (schemaFile != null)
    {
      modifiedSchemaFiles.add(schemaFile);
    }
  }
  /**
   * Handles all processing required for adding the provided DIT content rule to
   * the given schema, replacing an existing rule if necessary, and ensuring
   * all other metadata is properly updated.
   *
   * @param  ditContentRule       The DIT content rule to add or replace in the
   *                              server schema.
   * @param  schema               The schema to which the DIT content rule
   *                              should be be added.
   * @param  modifiedSchemaFiles  The names of the schema files containing
   *                              schema elements that have been updated as part
   *                              of the schema modification.
   *
   * @throws  DirectoryException  If a problem occurs while attempting to add
   *                              the provided DIT content rule to the server
   *                              schema.
   */
  private void addDITContentRule(DITContentRule ditContentRule, Schema schema,
                                 Set<String> modifiedSchemaFiles)
          throws DirectoryException
  {
    assert debugEnter(CLASS_NAME, "addDITContentRule",
                      String.valueOf(ditContentRule), String.valueOf(schema),
                      String.valueOf(modifiedSchemaFiles));
    // First, see if the specified DIT content rule already exists.  We'll check
    // all of the names, which means that it's possible there could be more than
    // one match (although if there is, then we'll refuse the operation).
    DITContentRule existingDCR = null;
    for (DITContentRule dcr : schema.getDITContentRules().values())
    {
      for (String name : ditContentRule.getNames().keySet())
      {
        if (dcr.hasName(name))
        {
          if (existingDCR == null)
          {
            existingDCR = dcr;
            break;
          }
          else
          {
            int    msgID   = MSGID_SCHEMA_MODIFY_MULTIPLE_CONFLICTS_FOR_ADD_DCR;
            String message = getMessage(msgID, ditContentRule.getName(),
                                        existingDCR.getName(),
                                        dcr.getName());
            throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM,
                                         message, msgID);
          }
        }
      }
    }
    // Get the structural class for the new DIT content rule and see if there's
    // already an existing rule that is associated with that class.  If there
    // is, then it will only be acceptable if it's the DIT content rule that we
    // are replacing (in which case we really do want to use the "!=" operator).
    ObjectClass structuralClass = ditContentRule.getStructuralClass();
    DITContentRule existingRuleForClass =
         schema.getDITContentRule(structuralClass);
    if ((existingRuleForClass != null) && (existingRuleForClass != existingDCR))
    {
      int    msgID   = MSGID_SCHEMA_MODIFY_STRUCTURAL_OC_CONFLICT_FOR_ADD_DCR;
      String message = getMessage(msgID, ditContentRule.getName(),
                                  structuralClass.getNameOrOID(),
                                  existingRuleForClass.getName());
      throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message,
                                   msgID);
    }
    // Make sure that the new DIT content rule doesn't reference an undefined
    // structural or auxiliaryclass, or an undefined required, optional, or
    // prohibited attribute type.
    if (! schema.hasObjectClass(structuralClass.getOID()))
    {
      int    msgID   = MSGID_SCHEMA_MODIFY_DCR_UNDEFINED_STRUCTURAL_OC;
      String message = getMessage(msgID, ditContentRule.getName(),
                                  structuralClass.getNameOrOID());
      throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message,
                                   msgID);
    }
    if (structuralClass.getObjectClassType() != ObjectClassType.STRUCTURAL)
    {
      int    msgID   = MSGID_SCHEMA_MODIFY_DCR_OC_NOT_STRUCTURAL;
      String message = getMessage(msgID, ditContentRule.getName(),
                                  structuralClass.getNameOrOID());
      throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message,
                                   msgID);
    }
    for (ObjectClass oc : ditContentRule.getAuxiliaryClasses())
    {
      if (! schema.hasObjectClass(oc.getOID()))
      {
        int    msgID   = MSGID_SCHEMA_MODIFY_DCR_UNDEFINED_AUXILIARY_OC;
        String message = getMessage(msgID, ditContentRule.getName(),
                                    oc.getNameOrOID());
        throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message,
                                     msgID);
      }
    }
    for (AttributeType at : ditContentRule.getRequiredAttributes())
    {
      if (! schema.hasAttributeType(at.getOID()))
      {
        int    msgID   = MSGID_SCHEMA_MODIFY_DCR_UNDEFINED_REQUIRED_ATTR;
        String message = getMessage(msgID, ditContentRule.getName(),
                                    at.getNameOrOID());
        throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message,
                                     msgID);
      }
    }
    for (AttributeType at : ditContentRule.getOptionalAttributes())
    {
      if (! schema.hasAttributeType(at.getOID()))
      {
        int    msgID   = MSGID_SCHEMA_MODIFY_DCR_UNDEFINED_OPTIONAL_ATTR;
        String message = getMessage(msgID, ditContentRule.getName(),
                                    at.getNameOrOID());
        throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message,
                                     msgID);
      }
    }
    for (AttributeType at : ditContentRule.getProhibitedAttributes())
    {
      if (! schema.hasAttributeType(at.getOID()))
      {
        int    msgID   = MSGID_SCHEMA_MODIFY_DCR_UNDEFINED_PROHIBITED_ATTR;
        String message = getMessage(msgID, ditContentRule.getName(),
                                    at.getNameOrOID());
        throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message,
                                     msgID);
      }
    }
    // If there is no existing rule, then we're adding a new DIT content rule.
    // Otherwise, we're replacing an existing one.
    if (existingDCR == null)
    {
      schema.registerDITContentRule(ditContentRule, false);
      String schemaFile = ditContentRule.getSchemaFile();
      if ((schemaFile == null) || (schemaFile.length() == 0))
      {
        schemaFile = FILE_USER_SCHEMA_ELEMENTS;
        ditContentRule.setSchemaFile(schemaFile);
      }
      modifiedSchemaFiles.add(schemaFile);
    }
    else
    {
      schema.deregisterDITContentRule(existingDCR);
      schema.registerDITContentRule(ditContentRule, false);
      schema.rebuildDependentElements(existingDCR);
      if ((ditContentRule.getSchemaFile() == null) ||
          (ditContentRule.getSchemaFile().length() == 0))
      {
        String schemaFile = existingDCR.getSchemaFile();
        if ((schemaFile == null) || (schemaFile.length() == 0))
        {
          schemaFile = FILE_USER_SCHEMA_ELEMENTS;
        }
        ditContentRule.setSchemaFile(schemaFile);
        modifiedSchemaFiles.add(schemaFile);
      }
      else
      {
        String newSchemaFile = ditContentRule.getSchemaFile();
        String oldSchemaFile = existingDCR.getSchemaFile();
        if ((oldSchemaFile == null) || oldSchemaFile.equals(newSchemaFile))
        {
          modifiedSchemaFiles.add(newSchemaFile);
        }
        else
        {
          modifiedSchemaFiles.add(newSchemaFile);
          modifiedSchemaFiles.add(oldSchemaFile);
        }
      }
    }
  }
  /**
   * Handles all processing required to remove the provided DIT content rule
   * from the server schema, ensuring all other metadata is properly updated.
   * Note that this method will first check to see whether the same rule will be
   * later added to the server schema with an updated definition, and if so then
   * the removal will be ignored because the later add will be handled as a
   * replace.  If the DIT content rule will not be replaced with a new
   * definition, then this method will ensure that there are no other schema
   * elements that depend on the rule before allowing it to be removed.
   *
   * @param  ditContentRule       The DIT content rule to remove from the server
   *                              schema.
   * @param  schema               The schema from which the DIT content rule
   *                              should be removed.
   * @param  modifications        The full set of modifications to be processed
   *                              against the server schema.
   * @param  currentPosition      The position of the modification currently
   *                              being performed.
   * @param  modifiedSchemaFiles  The names of the schema files containing
   *                              schema elements that have been updated as part
   *                              of the schema modification.
   *
   * @throws  DirectoryException  If a problem occurs while attempting to remove
   *                              the provided DIT content rule from the server
   *                              schema.
   */
  private void removeDITContentRule(DITContentRule ditContentRule,
                                    Schema schema,
                                    ArrayList<Modification> modifications,
                                    int currentPosition,
                                    Set<String> modifiedSchemaFiles)
          throws DirectoryException
  {
    assert debugEnter(CLASS_NAME, "removeDITContentRule",
                      String.valueOf(ditContentRule), String.valueOf(schema),
                      String.valueOf(modifications),
                      String.valueOf(currentPosition),
                      String.valueOf(modifiedSchemaFiles));
    // See if the specified DIT content rule is actually defined in the server
    // schema.  If not, then fail.
    DITContentRule removeDCR =
         schema.getDITContentRule(ditContentRule.getStructuralClass());
    if ((removeDCR == null) || (! removeDCR.equals(ditContentRule)))
    {
      int    msgID   = MSGID_SCHEMA_MODIFY_REMOVE_NO_SUCH_DCR;
      String message = getMessage(msgID, ditContentRule.getName());
      throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message,
                                   msgID);
    }
    // Since DIT content rules don't have any dependencies, then we don't need
    // to worry about the difference between a remove or a replace.  We can
    // just remove the DIT content rule now, and if it is added back later then
    // there still won't be any conflict.
    schema.deregisterDITContentRule(removeDCR);
    String schemaFile = removeDCR.getSchemaFile();
    if (schemaFile != null)
    {
      modifiedSchemaFiles.add(schemaFile);
    }
  }
  /**
   * Handles all processing required for adding the provided DIT structure rule
   * to the given schema, replacing an existing rule if necessary, and ensuring
   * all other metadata is properly updated.
   *
   * @param  ditStructureRule     The DIT structure rule to add or replace in
   *                              the server schema.
   * @param  schema               The schema to which the DIT structure rule
   *                              should be be added.
   * @param  modifiedSchemaFiles  The names of the schema files containing
   *                              schema elements that have been updated as part
   *                              of the schema modification.
   *
   * @throws  DirectoryException  If a problem occurs while attempting to add
   *                              the provided DIT structure rule to the server
   *                              schema.
   */
  private void addDITStructureRule(DITStructureRule ditStructureRule,
                                   Schema schema,
                                   Set<String> modifiedSchemaFiles)
          throws DirectoryException
  {
    assert debugEnter(CLASS_NAME, "addDITStructureRule",
                      String.valueOf(ditStructureRule), String.valueOf(schema),
                      String.valueOf(modifiedSchemaFiles));
    // First, see if the specified DIT structure rule already exists.  We'll
    // check the rule ID and all of the names, which means that it's possible
    // there could be more than one match (although if there is, then we'll
    // refuse the operation).
    DITStructureRule existingDSR =
         schema.getDITStructureRule(ditStructureRule.getRuleID());
    for (DITStructureRule dsr : schema.getDITStructureRulesByID().values())
    {
      for (String name : ditStructureRule.getNames().keySet())
      {
        if (dsr.hasName(name))
        {
          // We really do want to use the "!=" operator here because it's
          // acceptable if we find match for the same object instance.
          if ((existingDSR != null) && (existingDSR != dsr))
          {
            int    msgID   = MSGID_SCHEMA_MODIFY_MULTIPLE_CONFLICTS_FOR_ADD_DSR;
            String message = getMessage(msgID,
                                        ditStructureRule.getNameOrRuleID(),
                                        existingDSR.getNameOrRuleID(),
                                        dsr.getNameOrRuleID());
            throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM,
                                         message, msgID);
          }
        }
      }
    }
    // Get the name form for the new DIT structure rule and see if there's
    // already an existing rule that is associated with that name form.  If
    // there is, then it will only be acceptable if it's the DIT structure rule
    // that we are replacing (in which case we really do want to use the "!="
    // operator).
    NameForm nameForm = ditStructureRule.getNameForm();
    DITStructureRule existingRuleForNameForm =
         schema.getDITStructureRule(nameForm);
    if ((existingRuleForNameForm != null) &&
        (existingRuleForNameForm != existingDSR))
    {
      int    msgID   = MSGID_SCHEMA_MODIFY_NAME_FORM_CONFLICT_FOR_ADD_DSR;
      String message = getMessage(msgID, ditStructureRule.getNameOrRuleID(),
                                  nameForm.getNameOrOID(),
                                  existingRuleForNameForm.getNameOrRuleID());
      throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message,
                                   msgID);
    }
    // Make sure that the new DIT structure rule doesn't reference an undefined
    // name form or superior DIT structure rule.
    if (! schema.hasNameForm(nameForm.getOID()))
    {
      int    msgID   = MSGID_SCHEMA_MODIFY_DSR_UNDEFINED_NAME_FORM;
      String message = getMessage(msgID, ditStructureRule.getNameOrRuleID(),
                                  nameForm.getNameOrOID());
      throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message,
                                   msgID);
    }
    // If there is no existing rule, then we're adding a new DIT structure rule.
    // Otherwise, we're replacing an existing one.
    if (existingDSR == null)
    {
      schema.registerDITStructureRule(ditStructureRule, false);
      String schemaFile = ditStructureRule.getSchemaFile();
      if ((schemaFile == null) || (schemaFile.length() == 0))
      {
        schemaFile = FILE_USER_SCHEMA_ELEMENTS;
        ditStructureRule.setSchemaFile(schemaFile);
      }
      modifiedSchemaFiles.add(schemaFile);
    }
    else
    {
      schema.deregisterDITStructureRule(existingDSR);
      schema.registerDITStructureRule(ditStructureRule, false);
      schema.rebuildDependentElements(existingDSR);
      if ((ditStructureRule.getSchemaFile() == null) ||
          (ditStructureRule.getSchemaFile().length() == 0))
      {
        String schemaFile = existingDSR.getSchemaFile();
        if ((schemaFile == null) || (schemaFile.length() == 0))
        {
          schemaFile = FILE_USER_SCHEMA_ELEMENTS;
        }
        ditStructureRule.setSchemaFile(schemaFile);
        modifiedSchemaFiles.add(schemaFile);
      }
      else
      {
        String newSchemaFile = ditStructureRule.getSchemaFile();
        String oldSchemaFile = existingDSR.getSchemaFile();
        if ((oldSchemaFile == null) || oldSchemaFile.equals(newSchemaFile))
        {
          modifiedSchemaFiles.add(newSchemaFile);
        }
        else
        {
          modifiedSchemaFiles.add(newSchemaFile);
          modifiedSchemaFiles.add(oldSchemaFile);
        }
      }
    }
  }
  /**
   * Handles all processing required to remove the provided DIT structure rule
   * from the server schema, ensuring all other metadata is properly updated.
   * Note that this method will first check to see whether the same rule will be
   * later added to the server schema with an updated definition, and if so then
   * the removal will be ignored because the later add will be handled as a
   * replace.  If the DIT structure rule will not be replaced with a new
   * definition, then this method will ensure that there are no other schema
   * elements that depend on the rule before allowing it to be removed.
   *
   * @param  ditStructureRule     The DIT structure rule to remove from the
   *                              server schema.
   * @param  schema               The schema from which the DIT structure rule
   *                              should be removed.
   * @param  modifications        The full set of modifications to be processed
   *                              against the server schema.
   * @param  currentPosition      The position of the modification currently
   *                              being performed.
   * @param  modifiedSchemaFiles  The names of the schema files containing
   *                              schema elements that have been updated as part
   *                              of the schema modification.
   *
   * @throws  DirectoryException  If a problem occurs while attempting to remove
   *                              the provided DIT structure rule from the
   *                              server schema.
   */
  private void removeDITStructureRule(DITStructureRule ditStructureRule,
                                      Schema schema,
                                      ArrayList<Modification> modifications,
                                      int currentPosition,
                                      Set<String> modifiedSchemaFiles)
          throws DirectoryException
  {
    assert debugEnter(CLASS_NAME, "removeDITStructureRule",
                      String.valueOf(ditStructureRule), String.valueOf(schema),
                      String.valueOf(modifications),
                      String.valueOf(currentPosition),
                      String.valueOf(modifiedSchemaFiles));
    // See if the specified DIT structure rule is actually defined in the server
    // schema.  If not, then fail.
    DITStructureRule removeDSR =
         schema.getDITStructureRule(ditStructureRule.getRuleID());
    if ((removeDSR == null) || (! removeDSR.equals(ditStructureRule)))
    {
      int    msgID   = MSGID_SCHEMA_MODIFY_REMOVE_NO_SUCH_DSR;
      String message = getMessage(msgID, ditStructureRule.getNameOrRuleID());
      throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message,
                                   msgID);
    }
    // See if there is another modification later to add the DIT structure rule
    // back into the schema.  If so, then it's a replace and we should ignore
    // the remove because adding it back will handle the replace.
    for (int i=currentPosition+1; i < modifications.size(); i++)
    {
      Modification m = modifications.get(i);
      Attribute    a = m.getAttribute();
      if ((m.getModificationType() != ModificationType.ADD) ||
          (! a.getAttributeType().equals(ditStructureRulesType)))
      {
        continue;
      }
      for (AttributeValue v : a.getValues())
      {
        DITStructureRule dsr;
        try
        {
          dsr = DITStructureRuleSyntax.decodeDITStructureRule(
                     v.getValue(), schema, false);
        }
        catch (DirectoryException de)
        {
          assert debugException(CLASS_NAME, "removeDITStructureRule", de);
          int msgID = MSGID_SCHEMA_MODIFY_CANNOT_DECODE_DSR;
          String message = getMessage(msgID, v.getStringValue(),
                                      de.getErrorMessage());
          throw new DirectoryException(
                         ResultCode.INVALID_ATTRIBUTE_SYNTAX, message,
                         msgID, de);
        }
        if (ditStructureRule.getRuleID() == dsr.getRuleID())
        {
          // We found a match where the DIT structure rule is added back later,
          // so we don't need to do anything else here.
          return;
        }
      }
    }
    // Make sure that the DIT structure rule isn't the superior for any other
    // DIT structure rule.
    for (DITStructureRule dsr : schema.getDITStructureRulesByID().values())
    {
      if (dsr.getSuperiorRules().contains(removeDSR))
      {
        int    msgID   = MSGID_SCHEMA_MODIFY_REMOVE_DSR_SUPERIOR_RULE;
        String message = getMessage(msgID, removeDSR.getNameOrRuleID(),
                                    dsr.getNameOrRuleID());
        throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message,
                                     msgID);
      }
    }
    // If we've gotten here, then it's OK to remove the DIT structure rule from
    // the schema.
    schema.deregisterDITStructureRule(removeDSR);
    String schemaFile = removeDSR.getSchemaFile();
    if (schemaFile != null)
    {
      modifiedSchemaFiles.add(schemaFile);
    }
  }
  /**
   * Handles all processing required for adding the provided matching rule use
   * to the given schema, replacing an existing use if necessary, and ensuring
   * all other metadata is properly updated.
   *
   * @param  matchingRuleUse      The matching rule use to add or replace in the
   *                              server schema.
   * @param  schema               The schema to which the matching rule use
   *                              should be added.
   * @param  modifiedSchemaFiles  The names of the schema files containing
   *                              schema elements that have been updated as part
   *                              of the schema modification.
   *
   * @throws  DirectoryException  If a problem occurs while attempting to add
   *                              the provided matching rule use to the server
   *                              schema.
   */
  private void addMatchingRuleUse(MatchingRuleUse matchingRuleUse,
                                  Schema schema,
                                  Set<String> modifiedSchemaFiles)
          throws DirectoryException
  {
    assert debugEnter(CLASS_NAME, "addMatchingRuleUse",
                      String.valueOf(matchingRuleUse), String.valueOf(schema),
                      String.valueOf(modifiedSchemaFiles));
    // First, see if the specified matching rule use already exists.  We'll
    // check all of the names, which means that it's possible that there could
    // be more than one match (although if there is, then we'll refuse the
    // operation).
    MatchingRuleUse existingMRU = null;
    for (MatchingRuleUse mru : schema.getMatchingRuleUses().values())
    {
      for (String name : matchingRuleUse.getNames().keySet())
      {
        if (mru.hasName(name))
        {
          if (existingMRU == null)
          {
            existingMRU = mru;
            break;
          }
          else
          {
            int msgID = MSGID_SCHEMA_MODIFY_MULTIPLE_CONFLICTS_FOR_ADD_MR_USE;
            String message = getMessage(msgID, matchingRuleUse.getName(),
                                        existingMRU.getName(), mru.getName());
            throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM,
                                         message, msgID);
          }
        }
      }
    }
    // Get the matching rule for the new matching rule use and see if there's
    // already an existing matching rule use that is associated with that
    // matching rule.  If there is, then it will only be acceptable if it's the
    // matching rule use that we are replacing (in which case we really do want
    // to use the "!=" operator).
    MatchingRule matchingRule = matchingRuleUse.getMatchingRule();
    MatchingRuleUse existingMRUForRule =
         schema.getMatchingRuleUse(matchingRule);
    if ((existingMRUForRule != null) && (existingMRUForRule != existingMRU))
    {
      int    msgID   = MSGID_SCHEMA_MODIFY_MR_CONFLICT_FOR_ADD_MR_USE;
      String message = getMessage(msgID, matchingRuleUse.getName(),
                                  matchingRule.getNameOrOID(),
                                  existingMRUForRule.getName());
      throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message,
                                   msgID);
    }
    // Make sure that the new matching rule use doesn't reference an undefined
    // attribute type.
    for (AttributeType at : matchingRuleUse.getAttributes())
    {
      if (! schema.hasAttributeType(at.getOID()))
      {
        int    msgID   = MSGID_SCHEMA_MODIFY_MRU_UNDEFINED_ATTR;
        String message = getMessage(msgID, matchingRuleUse.getName(),
                                    at.getNameOrOID());
        throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message,
                                     msgID);
      }
    }
    // If there is no existing matching rule use, then we're adding a new one.
    // Otherwise, we're replacing an existing matching rule use.
    if (existingMRU == null)
    {
      schema.registerMatchingRuleUse(matchingRuleUse, false);
      String schemaFile = matchingRuleUse.getSchemaFile();
      if ((schemaFile == null) || (schemaFile.length() == 0))
      {
        schemaFile = FILE_USER_SCHEMA_ELEMENTS;
        matchingRuleUse.setSchemaFile(schemaFile);
      }
      modifiedSchemaFiles.add(schemaFile);
    }
    else
    {
      schema.deregisterMatchingRuleUse(existingMRU);
      schema.registerMatchingRuleUse(matchingRuleUse, false);
      schema.rebuildDependentElements(existingMRU);
      if ((matchingRuleUse.getSchemaFile() == null) ||
          (matchingRuleUse.getSchemaFile().length() == 0))
      {
        String schemaFile = existingMRU.getSchemaFile();
        if ((schemaFile == null) || (schemaFile.length() == 0))
        {
          schemaFile = FILE_USER_SCHEMA_ELEMENTS;
        }
        matchingRuleUse.setSchemaFile(schemaFile);
        modifiedSchemaFiles.add(schemaFile);
      }
      else
      {
        String newSchemaFile = matchingRuleUse.getSchemaFile();
        String oldSchemaFile = existingMRU.getSchemaFile();
        if ((oldSchemaFile == null) || oldSchemaFile.equals(newSchemaFile))
        {
          modifiedSchemaFiles.add(newSchemaFile);
        }
        else
        {
          modifiedSchemaFiles.add(newSchemaFile);
          modifiedSchemaFiles.add(oldSchemaFile);
        }
      }
    }
  }
  /**
   * Handles all processing required to remove the provided matching rule use
   * from the server schema, ensuring all other metadata is properly updated.
   * Note that this method will first check to see whether the same matching
   * rule use will be later added to the server schema with an updated
   * definition, and if so then the removal will be ignored because the later
   * add will be handled as a replace.  If the matching rule use will not be
   * replaced with a new definition, then this method will ensure that there are
   * no other schema elements that depend on the matching rule use before
   * allowing it to be removed.
   *
   * @param  matchingRuleUse      The matching rule use to remove from the
   *                              server schema.
   * @param  schema               The schema from which the matching rule use
   *                              should be removed.
   * @param  modifications        The full set of modifications to be processed
   *                              against the server schema.
   * @param  currentPosition      The position of the modification currently
   *                              being performed.
   * @param  modifiedSchemaFiles  The names of the schema files containing
   *                              schema elements that have been updated as part
   *                              of the schema modification.
   *
   * @throws  DirectoryException  If a problem occurs while attempting to remove
   *                              the provided matching rule use from the server
   *                              schema.
   */
  private void removeMatchingRuleUse(MatchingRuleUse matchingRuleUse,
                                     Schema schema,
                                     ArrayList<Modification> modifications,
                                     int currentPosition,
                                     Set<String> modifiedSchemaFiles)
          throws DirectoryException
  {
    assert debugEnter(CLASS_NAME, "removeMatchingRuleUse",
                      String.valueOf(matchingRuleUse), String.valueOf(schema),
                      String.valueOf(modifications),
                      String.valueOf(currentPosition),
                      String.valueOf(modifiedSchemaFiles));
    // See if the specified DIT content rule is actually defined in the server
    // schema.  If not, then fail.
    MatchingRuleUse removeMRU =
         schema.getMatchingRuleUse(matchingRuleUse.getMatchingRule());
    if ((removeMRU == null) || (! removeMRU.equals(matchingRuleUse)))
    {
      int    msgID   = MSGID_SCHEMA_MODIFY_REMOVE_NO_SUCH_MR_USE;
      String message = getMessage(msgID, matchingRuleUse.getName());
      throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message,
                                   msgID);
    }
    // Since matching rule uses don't have any dependencies, then we don't need
    // to worry about the difference between a remove or a replace.  We can
    // just remove the DIT content rule now, and if it is added back later then
    // there still won't be any conflict.
    schema.deregisterMatchingRuleUse(removeMRU);
    String schemaFile = removeMRU.getSchemaFile();
    if (schemaFile != null)
    {
      modifiedSchemaFiles.add(schemaFile);
    }
  }
@@ -1215,6 +2961,661 @@
  /**
   * Writes a temporary version of the specified schema file.
   *
   * @param  schema      The schema from which to take the definitions to be
   *                     written.
   * @param  schemaFile  The name of the schema file to be written.
   *
   * @throws  DirectoryException  If an unexpected problem occurs while
   *                              identifying the schema definitions to include
   *                              in the schema file.
   *
   * @throws  IOException  If an unexpected error occurs while attempting to
   *                       write the temporary schema file.
   *
   * @throws  LDIFException  If an unexpected problem occurs while generating
   *                         the LDIF representation of the schema entry.
   */
  private File writeTempSchemaFile(Schema schema, String schemaFile)
          throws DirectoryException, IOException, LDIFException
  {
    assert debugEnter(CLASS_NAME, "writeTempSchemaFile", String.valueOf(schema),
                      String.valueOf(schemaFile));
    // Start with an empty schema entry.
    Entry schemaEntry = createEmptySchemaEntry();
    // 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>();
    for (AttributeType at : schema.getAttributeTypes().values())
    {
      if (schemaFile.equals(at.getSchemaFile()))
      {
        addAttrTypeToSchemaFile(schema, schemaFile, at, values, addedTypes, 0);
      }
    }
    if (! values.isEmpty())
    {
      ArrayList<Attribute> attrList = new ArrayList<Attribute>(1);
      attrList.add(new Attribute(attributeTypesType,
                                 attributeTypesType.getPrimaryName(), values));
      schemaEntry.putAttribute(attributeTypesType, attrList);
    }
    // Add all of the appropriate objectclasses to the schema entry.  We need
    // to be careful of the ordering to ensure that any superior classes in the
    // same file are written before the subordinate classes.
    HashSet<ObjectClass> addedClasses = new HashSet<ObjectClass>();
    values = new LinkedHashSet<AttributeValue>();
    for (ObjectClass oc : schema.getObjectClasses().values())
    {
      if (schemaFile.equals(oc.getSchemaFile()))
      {
        addObjectClassToSchemaFile(schema, schemaFile, oc, values, addedClasses,
                                   0);
      }
    }
    if (! values.isEmpty())
    {
      ArrayList<Attribute> attrList = new ArrayList<Attribute>(1);
      attrList.add(new Attribute(objectClassesType,
                                 objectClassesType.getPrimaryName(), values));
      schemaEntry.putAttribute(objectClassesType, attrList);
    }
    // Add all of the appropriate name forms to the schema entry.  Since there
    // is no hierarchical relationship between name forms, we don't need to
    // worry about ordering.
    values = new LinkedHashSet<AttributeValue>();
    for (NameForm nf : schema.getNameFormsByObjectClass().values())
    {
      if (schemaFile.equals(nf.getSchemaFile()))
      {
        values.add(new AttributeValue(nameFormsType, nf.getDefinition()));
      }
    }
    if (! values.isEmpty())
    {
      ArrayList<Attribute> attrList = new ArrayList<Attribute>(1);
      attrList.add(new Attribute(nameFormsType,
                                 nameFormsType.getPrimaryName(), values));
      schemaEntry.putAttribute(nameFormsType, attrList);
    }
    // Add all of the appropriate DIT content rules to the schema entry.  Since
    // there is no hierarchical relationship between DIT content rules, we don't
    // need to worry about ordering.
    values = new LinkedHashSet<AttributeValue>();
    for (DITContentRule dcr : schema.getDITContentRules().values())
    {
      if (schemaFile.equals(dcr.getSchemaFile()))
      {
        values.add(new AttributeValue(ditContentRulesType,
                                      dcr.getDefinition()));
      }
    }
    if (! values.isEmpty())
    {
      ArrayList<Attribute> attrList = new ArrayList<Attribute>(1);
      attrList.add(new Attribute(ditContentRulesType,
                                 ditContentRulesType.getPrimaryName(), values));
      schemaEntry.putAttribute(ditContentRulesType, attrList);
    }
    // Add all of the appropriate DIT structure rules to the schema entry.  We
    // need to be careful of the ordering to ensure that any superior rules in
    // the same file are written before the subordinate rules.
    HashSet<DITStructureRule> addedDSRs = new HashSet<DITStructureRule>();
    values = new LinkedHashSet<AttributeValue>();
    for (DITStructureRule dsr : schema.getDITStructureRulesByID().values())
    {
      if (schemaFile.equals(dsr.getSchemaFile()))
      {
        addDITStructureRuleToSchemaFile(schema, schemaFile, dsr, values,
                                        addedDSRs, 0);
      }
    }
    if (! values.isEmpty())
    {
      ArrayList<Attribute> attrList = new ArrayList<Attribute>(1);
      attrList.add(new Attribute(ditStructureRulesType,
                                 ditStructureRulesType.getPrimaryName(),
                                 values));
      schemaEntry.putAttribute(ditStructureRulesType, attrList);
    }
    // Add all of the appropriate matching rule uses to the schema entry.  Since
    // there is no hierarchical relationship between matching rule uses, we
    // don't need to worry about ordering.
    values = new LinkedHashSet<AttributeValue>();
    for (MatchingRuleUse mru : schema.getMatchingRuleUses().values())
    {
      if (schemaFile.equals(mru.getSchemaFile()))
      {
        values.add(new AttributeValue(matchingRuleUsesType,
                                      mru.getDefinition()));
      }
    }
    if (! values.isEmpty())
    {
      ArrayList<Attribute> attrList = new ArrayList<Attribute>(1);
      attrList.add(new Attribute(matchingRuleUsesType,
                                 matchingRuleUsesType.getPrimaryName(),
                                 values));
      schemaEntry.putAttribute(matchingRuleUsesType, attrList);
    }
    // Create a temporary file to which we can write the schema entry.
    File tempFile = File.createTempFile(schemaFile, "temp");
    LDIFExportConfig exportConfig =
         new LDIFExportConfig(tempFile.getAbsolutePath(),
                              ExistingFileBehavior.OVERWRITE);
    LDIFWriter ldifWriter = new LDIFWriter(exportConfig);
    ldifWriter.writeEntry(schemaEntry);
    ldifWriter.close();
    return tempFile;
  }
  /**
   * Adds the definition for the specified attribute type to the provided set of
   * attribute values, recursively adding superior types as appropriate.
   *
   * @param  schema         The schema containing the attribute type.
   * @param  schemaFile     The schema file with which the attribute type is
   *                        associated.
   * @param  attributeType  The attribute type whose definition should be added
   *                        to the value set.
   * @param  values         The set of values for attribute type definitions
   *                        already added.
   * @param  addedTypes     The set of attribute types whose definitions have
   *                        already been added to the set of values.
   * @param  depth          A depth counter to use in an attempt to detect
   *                        circular references.
   */
  private void addAttrTypeToSchemaFile(Schema schema, String schemaFile,
                                       AttributeType attributeType,
                                       LinkedHashSet<AttributeValue> values,
                                       HashSet<AttributeType> addedTypes,
                                       int depth)
          throws DirectoryException
  {
    assert debugEnter(CLASS_NAME, "addAttrTypeToSchemaFile",
                      String.valueOf(schema), String.valueOf(schemaFile),
                      String.valueOf(attributeType), String.valueOf(values),
                      String.valueOf(addedTypes), String.valueOf(depth));
    if (depth > 20)
    {
      int    msgID   = MSGID_SCHEMA_MODIFY_CIRCULAR_REFERENCE_AT;
      String message = getMessage(msgID, attributeType.getNameOrOID());
      throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message,
                                   msgID);
    }
    if (addedTypes.contains(attributeType))
    {
      return;
    }
    AttributeType superiorType = attributeType.getSuperiorType();
    if ((superiorType != null) &&
        schemaFile.equals(superiorType.getSchemaFile()) &&
        (! addedTypes.contains(superiorType)))
    {
      addAttrTypeToSchemaFile(schema, schemaFile, superiorType, values,
                              addedTypes, depth+1);
    }
    values.add(new AttributeValue(attributeTypesType,
                                  attributeType.getDefinition()));
    addedTypes.add(attributeType);
  }
  /**
   * Adds the definition for the specified objectclass to the provided set of
   * attribute values, recursively adding superior classes as appropriate.
   *
   * @param  schema        The schema containing the objectclass.
   * @param  schemaFile    The schema file with which the objectclass is
   *                       associated.
   * @param  objectClass   The objectclass whose definition should be added to
   *                       the value set.
   * @param  values        The set of values for objectclass definitions
   *                       already added.
   * @param  addedClasses  The set of objectclasses whose definitions have
   *                       already been added to the set of values.
   * @param  depth         A depth counter to use in an attempt to detect
   *                       circular references.
   */
  private void addObjectClassToSchemaFile(Schema schema, String schemaFile,
                                          ObjectClass objectClass,
                                          LinkedHashSet<AttributeValue> values,
                                          HashSet<ObjectClass> addedClasses,
                                          int depth)
          throws DirectoryException
  {
    assert debugEnter(CLASS_NAME, "addObjectClassToSchemaFile",
                      String.valueOf(schema), String.valueOf(schemaFile),
                      String.valueOf(objectClass), String.valueOf(values),
                      String.valueOf(addedClasses), String.valueOf(depth));
    if (depth > 20)
    {
      int    msgID   = MSGID_SCHEMA_MODIFY_CIRCULAR_REFERENCE_OC;
      String message = getMessage(msgID, objectClass.getNameOrOID());
      throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message,
                                   msgID);
    }
    if (addedClasses.contains(objectClass))
    {
      return;
    }
    ObjectClass superiorClass = objectClass.getSuperiorClass();
    if ((superiorClass != null) &&
        schemaFile.equals(superiorClass.getSchemaFile()) &&
        (! addedClasses.contains(superiorClass)))
    {
      addObjectClassToSchemaFile(schema, schemaFile, superiorClass, values,
                                 addedClasses, depth+1);
    }
    values.add(new AttributeValue(objectClassesType,
                                  objectClass.getDefinition()));
    addedClasses.add(objectClass);
  }
  /**
   * Adds the definition for the specified DIT structure rule to the provided
   * set of attribute values, recursively adding superior rules as appropriate.
   *
   * @param  schema            The schema containing the DIT structure rule.
   * @param  schemaFile        The schema file with which the DIT structure rule
   *                           is associated.
   * @param  ditStructureRule  The DIT structure rule whose definition should be
   *                           added to the value set.
   * @param  values            The set of values for DIT structure rule
   *                           definitions already added.
   * @param  addedDSRs         The set of DIT structure rules whose definitions
   *                           have already been added added to the set of
   *                           values.
   * @param  depth             A depth counter to use in an attempt to detect
   *                           circular references.
   */
  private void addDITStructureRuleToSchemaFile(Schema schema, String schemaFile,
                    DITStructureRule ditStructureRule,
                    LinkedHashSet<AttributeValue> values,
                    HashSet<DITStructureRule> addedDSRs, int depth)
          throws DirectoryException
  {
    assert debugEnter(CLASS_NAME, "addDITStructureRuleToSchemaFile",
                      String.valueOf(schema), String.valueOf(schemaFile),
                      String.valueOf(ditStructureRule), String.valueOf(values),
                      String.valueOf(addedDSRs), String.valueOf(depth));
    if (depth > 20)
    {
      int    msgID   = MSGID_SCHEMA_MODIFY_CIRCULAR_REFERENCE_DSR;
      String message = getMessage(msgID, ditStructureRule.getNameOrRuleID());
      throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message,
                                   msgID);
    }
    if (addedDSRs.contains(ditStructureRule))
    {
      return;
    }
    for (DITStructureRule dsr : ditStructureRule.getSuperiorRules())
    {
      if (schemaFile.equals(dsr.getSchemaFile()) && (! addedDSRs.contains(dsr)))
      {
        addDITStructureRuleToSchemaFile(schema, schemaFile, dsr, values,
                                        addedDSRs, depth+1);
      }
    }
    values.add(new AttributeValue(ditStructureRulesType,
                                  ditStructureRule.getDefinition()));
    addedDSRs.add(ditStructureRule);
  }
  /**
   * Moves the specified temporary schema files in place of the active versions.
   * If an error occurs in the process, then this method will attempt to restore
   * the original schema files if possible.
   *
   * @param  tempSchemaFiles  The set of temporary schema files to be activated.
   *
   * @throws  DirectoryException  If a problem occurs while attempting to
   *                              install the temporary schema files.
   */
  private void installSchemaFiles(HashMap<String,File> tempSchemaFiles)
          throws DirectoryException
  {
    assert debugEnter(CLASS_NAME, "installSchemaFiles",
                      String.valueOf(tempSchemaFiles));
    // Create lists that will hold the three types of files we'll be dealing
    // with (the temporary files that will be installed, the installed schema
    // files, and the previously-installed schema files).
    ArrayList<File> installedFileList = new ArrayList<File>();
    ArrayList<File> tempFileList      = new ArrayList<File>();
    ArrayList<File> origFileList      = new ArrayList<File>();
    File schemaDir = new File(SchemaConfigManager.getSchemaDirectoryPath());
    for (String name : tempSchemaFiles.keySet())
    {
      installedFileList.add(new File(schemaDir, name));
      tempFileList.add(tempSchemaFiles.get(name));
      origFileList.add(new File(schemaDir, name + ".orig"));
    }
    // If there are any old ".orig" files laying around from a previous
    // attempt, then try to clean them up.
    for (File f : origFileList)
    {
      if (f.exists())
      {
        f.delete();
      }
    }
    // Copy all of the currently-installed files with a ".orig" extension.  If
    // this fails, then try to clean up the copies.
    try
    {
      for (int i=0; i < installedFileList.size(); i++)
      {
        File installedFile = installedFileList.get(i);
        File origFile      = origFileList.get(i);
        if (installedFile.exists())
        {
          copyFile(installedFile, origFile);
        }
      }
    }
    catch (Exception e)
    {
      assert debugException(CLASS_NAME, "installSchemaFiles", e);
      boolean allCleaned = true;
      for (File f : origFileList)
      {
        try
        {
          if (f.exists())
          {
            if (! f.delete())
            {
              allCleaned = false;
            }
          }
        }
        catch (Exception e2)
        {
          assert debugException(CLASS_NAME, "installSchemaFiles", e2);
          allCleaned = false;
        }
      }
      if (allCleaned)
      {
        int    msgID   = MSGID_SCHEMA_MODIFY_CANNOT_WRITE_ORIG_FILES_CLEANED;
        String message = getMessage(msgID, stackTraceToSingleLineString(e));
        throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
                                     message, msgID, e);
      }
      else
      {
        int msgID = MSGID_SCHEMA_MODIFY_CANNOT_WRITE_ORIG_FILES_NOT_CLEANED;
        String message = getMessage(msgID, stackTraceToSingleLineString(e));
        DirectoryServer.sendAlertNotification(this,
                             ALERT_TYPE_CANNOT_COPY_SCHEMA_FILES, msgID,
                             message);
        throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
                                     message, msgID, e);
      }
    }
    // Try to copy all of the temporary files into place over the installed
    // files.  If this fails, then try to restore the originals.
    try
    {
      for (int i=0; i < installedFileList.size(); i++)
      {
        File installedFile = installedFileList.get(i);
        File tempFile      = tempFileList.get(i);
        copyFile(tempFile, installedFile);
      }
    }
    catch (Exception e)
    {
      assert debugException(CLASS_NAME, "installSchemaFiles", e);
      for (File f : installedFileList)
      {
        try
        {
          if (f.exists())
          {
            f.delete();
          }
        }
        catch (Exception e2)
        {
          assert debugException(CLASS_NAME, "installSchemaFiles", e2);
        }
      }
      boolean allRestored = true;
      for (int i=0; i < installedFileList.size(); i++)
      {
        File installedFile = installedFileList.get(i);
        File origFile      = origFileList.get(i);
        try
        {
          if (origFile.exists())
          {
            if (! origFile.renameTo(installedFile))
            {
              allRestored = false;
            }
          }
        }
        catch (Exception e2)
        {
          assert debugException(CLASS_NAME, "installSchemaFiles", e2);
          allRestored = false;
        }
      }
      if (allRestored)
      {
        int    msgID   = MSGID_SCHEMA_MODIFY_CANNOT_WRITE_NEW_FILES_RESTORED;
        String message = getMessage(msgID, stackTraceToSingleLineString(e));
        throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
                                     message, msgID, e);
      }
      else
      {
        int msgID = MSGID_SCHEMA_MODIFY_CANNOT_WRITE_NEW_FILES_NOT_RESTORED;
        String message = getMessage(msgID, stackTraceToSingleLineString(e));
        DirectoryServer.sendAlertNotification(this,
                             ALERT_TYPE_CANNOT_WRITE_NEW_SCHEMA_FILES, msgID,
                             message);
        throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
                                     message, msgID, e);
      }
    }
    // At this point, we're committed to the schema change, so we can't throw
    // any more exceptions, but all we have left is to clean up the original and
    // temporary files.
    for (File f : origFileList)
    {
      try
      {
        if (f.exists())
        {
          f.delete();
        }
      }
      catch (Exception e)
      {
        assert debugException(CLASS_NAME, "installSchemaFiles", e);
      }
    }
    for (File f : tempFileList)
    {
      try
      {
        if (f.exists())
        {
          f.delete();
        }
      }
      catch (Exception e)
      {
        assert debugException(CLASS_NAME, "installSchemaFiles", e);
      }
    }
  }
  /**
   * Creates a copy of the specified file.
   *
   * @param  from  The source file to be copied.
   * @param  to    The destination file to be created.
   *
   * @throws  IOException  If a problem occurs.
   */
  private void copyFile(File from, File to)
          throws IOException
  {
    assert debugEnter(CLASS_NAME, "copyFile", String.valueOf(from),
                      String.valueOf(to));
    byte[]           buffer        = new byte[4096];
    FileInputStream  inputStream   = null;
    FileOutputStream outputStream  = null;
    try
    {
      inputStream  = new FileInputStream(from);
      outputStream = new FileOutputStream(to, false);
      int bytesRead = inputStream.read(buffer);
      while (bytesRead > 0)
      {
        outputStream.write(buffer, 0, bytesRead);
        bytesRead = inputStream.read(buffer);
      }
    }
    finally
    {
      if (inputStream != null)
      {
        try
        {
          inputStream.close();
        }
        catch (Exception e)
        {
          assert debugException(CLASS_NAME, "copyFile", e);
        }
      }
      if (outputStream != null)
      {
        outputStream.close();
      }
    }
  }
  /**
   * Performs any necessary cleanup in an attempt to delete any temporary schema
   * files that may have been left over after trying to install the new schema.
   *
   * @param  tempSchemaFiles  The set of temporary schema files that have been
   *                          created and are candidates for cleanup.
   */
  private void cleanUpTempSchemaFiles(HashMap<String,File> tempSchemaFiles)
  {
    assert debugEnter(CLASS_NAME, "cleanUpTempSchemaFiles",
                      String.valueOf(tempSchemaFiles));
    if ((tempSchemaFiles == null) || tempSchemaFiles.isEmpty())
    {
      return;
    }
    for (File f : tempSchemaFiles.values())
    {
      try
      {
        if (f.exists())
        {
          f.delete();
        }
      }
      catch (Exception e)
      {
        assert debugException(CLASS_NAME, "cleanUpTempSchemaFiles", e);
      }
    }
  }
  /**
   * Moves and/or renames the provided entry in this backend, altering any
   * subordinate entries as necessary.  This must ensure that an entry already
@@ -2795,5 +5196,63 @@
    this.showAllAttributes = showAllAttributes;
  }
  /**
   * Retrieves the DN of the configuration entry with which this alert generator
   * is associated.
   *
   * @return  The DN of the configuration entry with which this alert generator
   *          is associated.
   */
  public DN getComponentEntryDN()
  {
    assert debugEnter(CLASS_NAME, "getComponentEntryDN");
    return configEntryDN;
  }
  /**
   * Retrieves the fully-qualified name of the Java class for this alert
   * generator implementation.
   *
   * @return  The fully-qualified name of the Java class for this alert
   *          generator implementation.
   */
  public String getClassName()
  {
    assert debugEnter(CLASS_NAME, "getClassName");
    return CLASS_NAME;
  }
  /**
   * Retrieves information about the set of alerts that this generator may
   * produce.  The map returned should be between the notification type for a
   * particular notification and the human-readable description for that
   * notification.  This alert generator must not generate any alerts with types
   * that are not contained in this list.
   *
   * @return  Information about the set of alerts that this generator may
   *          produce.
   */
  public LinkedHashMap<String,String> getAlerts()
  {
    assert debugEnter(CLASS_NAME, "getAlerts");
    LinkedHashMap<String,String> alerts = new LinkedHashMap<String,String>();
    alerts.put(ALERT_TYPE_CANNOT_COPY_SCHEMA_FILES,
               ALERT_DESCRIPTION_CANNOT_COPY_SCHEMA_FILES);
    alerts.put(ALERT_TYPE_CANNOT_WRITE_NEW_SCHEMA_FILES,
               ALERT_DESCRIPTION_CANNOT_WRITE_NEW_SCHEMA_FILES);
    return alerts;
  }
}
opendj-sdk/opends/src/server/org/opends/server/core/DirectoryServer.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2006 Sun Microsystems, Inc.
 *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
 */
package org.opends.server.core;
@@ -2905,10 +2905,16 @@
         directoryServer.schema.getObjectClass(TOP_OBJECTCLASS_NAME);
    if (objectClass == null)
    {
      objectClass = new ObjectClass(TOP_OBJECTCLASS_NAME, Collections
          .singleton(TOP_OBJECTCLASS_NAME), TOP_OBJECTCLASS_OID,
          TOP_OBJECTCLASS_DESCRIPTION, null, null, null,
          ObjectClassType.ABSTRACT, false, null);
      String definition =
           "( 2.5.6.0 NAME 'top' ABSTRACT MUST objectClass " +
           "X-ORIGIN 'RFC 2256' )";
      objectClass = new ObjectClass(definition, TOP_OBJECTCLASS_NAME,
                                    Collections.singleton(TOP_OBJECTCLASS_NAME),
                                    TOP_OBJECTCLASS_OID,
                                    TOP_OBJECTCLASS_DESCRIPTION, null, null,
                                    null, ObjectClassType.ABSTRACT, false,
                                    null);
    }
    return objectClass;
@@ -2937,10 +2943,13 @@
    ObjectClass objectClass = directoryServer.schema.getObjectClass(lowerName);
    if (objectClass == null)
    {
      objectClass = new ObjectClass(name,
          Collections.singleton(name), lowerName, null,
          getTopObjectClass(), null, null, ObjectClassType.ABSTRACT,
          false, null);
      String oid        = lowerName + "-oid";
      String definition = "( " + oid + " NAME '" + name + "' ABSTRACT )";
      objectClass = new ObjectClass(definition, name,
                                    Collections.singleton(name), oid, null,
                                    getTopObjectClass(), null, null,
                                    ObjectClassType.ABSTRACT, false, null);
    }
    return objectClass;
@@ -3109,8 +3118,12 @@
          }
        }
        String definition =
             "( 2.5.4.0 NAME 'objectClass' EQUALITY objectIdentifierMatch " +
             "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 X-ORIGIN 'RFC 2256' )";
        directoryServer.objectClassAttributeType =
             new AttributeType("objectClass",
             new AttributeType(definition, "objectClass",
                               Collections.singleton("objectClass"),
                               OBJECTCLASS_ATTRIBUTE_TYPE_OID, null, null,
                               oidSyntax, AttributeUsage.USER_APPLICATIONS,
@@ -3172,9 +3185,12 @@
                      String.valueOf(name));
    String lowerName = toLowerCase(name);
    return new AttributeType(name, Collections.singleton(name),
                             lowerName, null, null, syntax,
    String oid        = toLowerCase(name) + "-oid";
    String definition = "( " + oid + " NAME '" + name + "' SYNTAX " +
                        syntax.getOID() + " )";
    return new AttributeType(definition, name, Collections.singleton(name),
                             oid, null, null, syntax,
                             AttributeUsage.USER_APPLICATIONS, false, false,
                             false, false);
  }
opendj-sdk/opends/src/server/org/opends/server/core/SchemaConfigManager.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2006 Sun Microsystems, Inc.
 *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
 */
package org.opends.server.core;
@@ -1247,7 +1247,8 @@
            DITStructureRule dsr;
            try
            {
              dsr = dsrSyntax.decodeDITStructureRule(v.getValue(), schema);
              dsr = dsrSyntax.decodeDITStructureRule(v.getValue(), schema,
                                                     false);
              dsr.getExtraProperties().remove(SCHEMA_PROPERTY_FILENAME);
              dsr.setSchemaFile(schemaFile);
            }
opendj-sdk/opends/src/server/org/opends/server/messages/BackendMessages.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2006 Sun Microsystems, Inc.
 *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
 */
package org.opends.server.messages;
@@ -2364,9 +2364,8 @@
  /**
   * The message ID for the message that will be used if an error occurs while
   * trying to write an updated schema file.  This takes two arguments, which
   * are the path to the schema file and a string representation of the
   * exception that was caught.
   * trying to write an updated schema file.  This takes a single argument,
   * which is a string representation of the exception that was caught.
   */
  public static final int MSGID_SCHEMA_MODIFY_CANNOT_WRITE_NEW_SCHEMA =
       CATEGORY_MASK_BACKEND | SEVERITY_MASK_MILD_ERROR | 222;
@@ -2374,6 +2373,595 @@
  /**
   * The message ID for the message that will be used if an error occurs while
   * attempting to decode a new name form.  This takes two arguments, which
   * are the name form string and a message explaining the problem that
   * occurred.
   */
  public static final int MSGID_SCHEMA_MODIFY_CANNOT_DECODE_NAME_FORM =
       CATEGORY_MASK_BACKEND | SEVERITY_MASK_MILD_ERROR | 223;
  /**
   * The message ID for the message that will be used if an error occurs while
   * attempting to decode a new DIT content rule.  This takes two arguments,
   * which are the DIT content rule string and a message explaining the problem
   * that occurred.
   */
  public static final int MSGID_SCHEMA_MODIFY_CANNOT_DECODE_DCR =
       CATEGORY_MASK_BACKEND | SEVERITY_MASK_MILD_ERROR | 224;
  /**
   * The message ID for the message that will be used if an error occurs while
   * attempting to decode a new DIT structure rule.  This takes two arguments,
   * which are the DIT structure rule string and a message explaining the
   * problem that occurred.
   */
  public static final int MSGID_SCHEMA_MODIFY_CANNOT_DECODE_DSR =
       CATEGORY_MASK_BACKEND | SEVERITY_MASK_MILD_ERROR | 225;
  /**
   * The message ID for the message that will be used if an error occurs while
   * attempting to decode a new matching rule use.  This takes two arguments,
   * which are the matching rule use string and a message explaining the problem
   * that occurred.
   */
  public static final int MSGID_SCHEMA_MODIFY_CANNOT_DECODE_MR_USE =
       CATEGORY_MASK_BACKEND | SEVERITY_MASK_MILD_ERROR | 226;
  /**
   * The message ID for the message that will be used if an attempt is made to
   * remove all values for a given attribute type.  This takes a single
   * argument, which is the name of that attribute type.
   */
  public static final int MSGID_SCHEMA_MODIFY_DELETE_NO_VALUES =
       CATEGORY_MASK_BACKEND | SEVERITY_MASK_MILD_ERROR | 227;
  /**
   * The message ID for the message that will be used if an attempt is made to
   * add a new attribute type that conflicts with multiple existing attribute
   * types.  This takes three arguments, which are the name or OID of the new
   * attribute type, and the name or OID of the two attribute types that were
   * found to conflict with the new type.
   */
  public static final int
       MSGID_SCHEMA_MODIFY_MULTIPLE_CONFLICTS_FOR_ADD_ATTRTYPE =
            CATEGORY_MASK_BACKEND | SEVERITY_MASK_MILD_ERROR | 228;
  /**
   * The message ID for the message that will be used if an attempt is made to
   * add a new attribute type that references an undefined superior attribute
   * type.  This takes two arguments, which are the name or OID of the new
   * attribute type and the name or OID of the superior attribute type.
   */
  public static final int
       MSGID_SCHEMA_MODIFY_UNDEFINED_SUPERIOR_ATTRIBUTE_TYPE =
            CATEGORY_MASK_BACKEND | SEVERITY_MASK_MILD_ERROR | 229;
  /**
   * The message ID for the message that will be used if an attempt is made to
   * add a new objectclas that conflicts with multiple existing objectclasses.
   * This takes three arguments, which are the name or OID of the new
   * objectclass, and the name or OID of the two objectclasses that were found
   * to conflict with the new objectclass.
   */
  public static final int
       MSGID_SCHEMA_MODIFY_MULTIPLE_CONFLICTS_FOR_ADD_OBJECTCLASS =
            CATEGORY_MASK_BACKEND | SEVERITY_MASK_MILD_ERROR | 230;
  /**
   * The message ID for the message that will be used if an attempt is made to
   * add a new name form that conflicts with multiple existing name forms.  This
   * takes three arguments, which are the name or OID of the new name form, and
   * the name or OID of the two name forms that were found to conflict with the
   * new name form.
   */
  public static final int
       MSGID_SCHEMA_MODIFY_MULTIPLE_CONFLICTS_FOR_ADD_NAME_FORM =
            CATEGORY_MASK_BACKEND | SEVERITY_MASK_MILD_ERROR | 231;
  /**
   * The message ID for the message that will be used if an attempt is made to
   * add a new name form that references an undefined structural objectclass.
   * This takes two arguments, which are the name or OID of the new name form
   * and the name or OID of the undefined objectclass.
   */
  public static final int MSGID_SCHEMA_MODIFY_NF_UNDEFINED_STRUCTURAL_OC =
       CATEGORY_MASK_BACKEND | SEVERITY_MASK_MILD_ERROR | 232;
  /**
   * The message ID for the message that will be used if an attempt is made to
   * add a new name form that references an undefined required attribute type.
   * This takes two arguments, which are the name or OID of the new name form
   * and the name or OID of the undefined attribute type.
   */
  public static final int MSGID_SCHEMA_MODIFY_NF_UNDEFINED_REQUIRED_ATTR =
       CATEGORY_MASK_BACKEND | SEVERITY_MASK_MILD_ERROR | 233;
  /**
   * The message ID for the message that will be used if an attempt is made to
   * add a new name form that references an undefined optional attribute type.
   * This takes two arguments, which are the name or OID of the new name form
   * and the name or OID of the undefined attribute type.
   */
  public static final int MSGID_SCHEMA_MODIFY_NF_UNDEFINED_OPTIONAL_ATTR =
       CATEGORY_MASK_BACKEND | SEVERITY_MASK_MILD_ERROR | 234;
  /**
   * The message ID for the message that will be used if an attempt is made to
   * add a new DIT content rule that conflicts with multiple existing DIT
   * content rules.  This takes three arguments, which are the name of the new
   * DIT content rule, and the names of the two DIT content rules that were
   * found to conflict with the new DIT content rule.
   */
  public static final int MSGID_SCHEMA_MODIFY_MULTIPLE_CONFLICTS_FOR_ADD_DCR =
       CATEGORY_MASK_BACKEND | SEVERITY_MASK_MILD_ERROR | 235;
  /**
   * The message ID for the message that will be used if an attempt is made to
   * add a new DIT content rule that references a structural objectclass which
   * is already referenced by an existing DIT copntent rule.  This takes three
   * arguments, which are the name of the new DIT content rule, the name or OID
   * of the structural objectclass, and the name of the conflicting DIT content
   * rule.
   */
  public static final int
       MSGID_SCHEMA_MODIFY_STRUCTURAL_OC_CONFLICT_FOR_ADD_DCR =
            CATEGORY_MASK_BACKEND | SEVERITY_MASK_MILD_ERROR | 236;
  /**
   * The message ID for the message that will be used if an attempt is made to
   * add a new DIT content rule that references a structural objectclass which
   * is not defined in the server schema.  This takes two arguments, which are
   * the name of the new DIT content rule and the name or OID of the undefined
   * objectclass.
   */
  public static final int MSGID_SCHEMA_MODIFY_DCR_UNDEFINED_STRUCTURAL_OC =
       CATEGORY_MASK_BACKEND | SEVERITY_MASK_MILD_ERROR | 237;
  /**
   * The message ID for the message that will be used if an attempt is made to
   * add a new DIT content rule that references an auxiliary objectclass which
   * is not defined in the server schema.  This takes two arguments, which are
   * the name of the new DIT content rule and the name or OID of the undefined
   * objectclass.
   */
  public static final int MSGID_SCHEMA_MODIFY_DCR_UNDEFINED_AUXILIARY_OC =
       CATEGORY_MASK_BACKEND | SEVERITY_MASK_MILD_ERROR | 238;
  /**
   * The message ID for the message that will be used if an attempt is made to
   * add a new DIT content rule that references a required attribute type
   * which is not defined in the server schema.  This takes two arguments, which
   * are the name of the new DIT content rule and the name or OID of the
   * undefined attribute type.
   */
  public static final int MSGID_SCHEMA_MODIFY_DCR_UNDEFINED_REQUIRED_ATTR =
       CATEGORY_MASK_BACKEND | SEVERITY_MASK_MILD_ERROR | 239;
  /**
   * The message ID for the message that will be used if an attempt is made to
   * add a new DIT content rule that references an optional attribute type
   * which is not defined in the server schema.  This takes two arguments, which
   * are the name of the new DIT content rule and the name or OID of the
   * undefined attribute type.
   */
  public static final int MSGID_SCHEMA_MODIFY_DCR_UNDEFINED_OPTIONAL_ATTR =
       CATEGORY_MASK_BACKEND | SEVERITY_MASK_MILD_ERROR | 240;
  /**
   * The message ID for the message that will be used if an attempt is made to
   * add a new DIT content rule that references a prohibited attribute type
   * which is not defined in the server schema.  This takes two arguments, which
   * are the name of the new DIT content rule and the name or OID of the
   * undefined attribute type.
   */
  public static final int MSGID_SCHEMA_MODIFY_DCR_UNDEFINED_PROHIBITED_ATTR =
       CATEGORY_MASK_BACKEND | SEVERITY_MASK_MILD_ERROR | 241;
  /**
   * The message ID for the message that will be used if an attempt is made to
   * add a new DIT structure rule that conflicts with multiple existing DIT
   * structure rules.  This takes three arguments, which are the name or rule ID
   * of the new DIT structure rule, and the names or rule IDs of the two DIT
   * structure rules that were found to conflict with the new DIT structure
   * rule.
   */
  public static final int MSGID_SCHEMA_MODIFY_MULTIPLE_CONFLICTS_FOR_ADD_DSR =
       CATEGORY_MASK_BACKEND | SEVERITY_MASK_MILD_ERROR | 242;
  /**
   * The message ID for the message that will be used if an attempt is made to
   * add a new DIT structure rule that references a name form that is already
   * referenced by another DIT structure rule.  This takes three arguemnts,
   * which are the name or rule ID of the new DIT structure rule, the name or
   * OID of the name form, and the name or rule ID of the conflicting DIT
   * structure rule.
   */
  public static final int MSGID_SCHEMA_MODIFY_NAME_FORM_CONFLICT_FOR_ADD_DSR =
       CATEGORY_MASK_BACKEND | SEVERITY_MASK_MILD_ERROR | 243;
  /**
   * The message ID for the message that will be used if an attempt is made to
   * add a new DIT structure rule that references a name form that is not
   * defined in the server schema.  This takes two arguments, which are the name
   * or rule ID of the new DIT structure rule and the name or OID of the
   * undefined name form.
   */
  public static final int MSGID_SCHEMA_MODIFY_DSR_UNDEFINED_NAME_FORM =
       CATEGORY_MASK_BACKEND | SEVERITY_MASK_MILD_ERROR | 244;
  /**
   * The message ID for the message that will be used if an attempt is made to
   * add a new matching rule use that conflicts with multiple existing matching
   * rule uses.  This takes three arguments, which are the name of the new
   * matching rule use, and the names of the two matching rule uses that were
   * found to conflict with the new matching rule use.
   */
  public static final int
       MSGID_SCHEMA_MODIFY_MULTIPLE_CONFLICTS_FOR_ADD_MR_USE =
            CATEGORY_MASK_BACKEND | SEVERITY_MASK_MILD_ERROR | 245;
  /**
   * The message ID for the message that will be used if an attempt is made to
   * add a new matching rule use that references a matching rule that is already
   * associated with another matching rule use.  This takes three arguments,
   * which are the name of the new matching rule use, the name or OID of the
   * matching rule, and the name of the conflicting matching rule use.
   */
  public static final int MSGID_SCHEMA_MODIFY_MR_CONFLICT_FOR_ADD_MR_USE =
       CATEGORY_MASK_BACKEND | SEVERITY_MASK_MILD_ERROR | 246;
  /**
   * The message ID for the message that will be used if an attempt is made to
   * add a new matching rule use that references an attribute type that is not
   * defined in the server schema.  This takes two arguments, which are the
   * name of the new matching rule use and the name or OID of the undefined
   * attribute type.
   */
  public static final int MSGID_SCHEMA_MODIFY_MRU_UNDEFINED_ATTR =
       CATEGORY_MASK_BACKEND | SEVERITY_MASK_MILD_ERROR | 247;
  /**
   * The message ID for the message that will be used if a circular reference
   * is detected in the superior chain for an attribute type.  This takes a
   * single argument, which is the name or OID of the attribute type.
   */
  public static final int MSGID_SCHEMA_MODIFY_CIRCULAR_REFERENCE_AT =
       CATEGORY_MASK_BACKEND | SEVERITY_MASK_MILD_ERROR | 248;
  /**
   * The message ID for the message that will be used if a circular reference
   * is detected in the superior chain for an objectclass.  This takes a single
   * argument, which is the name or OID of the objectclass.
   */
  public static final int MSGID_SCHEMA_MODIFY_CIRCULAR_REFERENCE_OC =
       CATEGORY_MASK_BACKEND | SEVERITY_MASK_MILD_ERROR | 249;
  /**
   * The message ID for the message that will be used if a circular reference
   * is detected in the superior chain for a DIT structure rule.  This takes a
   * single argument, which is the name or rule ID of the DIT structure rule.
   */
  public static final int MSGID_SCHEMA_MODIFY_CIRCULAR_REFERENCE_DSR =
       CATEGORY_MASK_BACKEND | SEVERITY_MASK_MILD_ERROR | 250;
  /**
   * The message ID for the message that will be used if an error occurs while
   * trying to create copies of the current schema files, but the server was
   * able to properly clean up after itself.  This takes a single argument,
   * which is a string representation of the exception that was caught.
   */
  public static final int MSGID_SCHEMA_MODIFY_CANNOT_WRITE_ORIG_FILES_CLEANED =
       CATEGORY_MASK_BACKEND | SEVERITY_MASK_MILD_ERROR | 251;
  /**
   * The message ID for the message that will be used if an error occurs while
   * trying to create copies of the current schema files, and the server was
   * not able to properly clean up after itself.  This takes a single argument,
   * which is a string representation of the exception that was caught.
   */
  public static final int
       MSGID_SCHEMA_MODIFY_CANNOT_WRITE_ORIG_FILES_NOT_CLEANED =
            CATEGORY_MASK_BACKEND | SEVERITY_MASK_MILD_ERROR | 252;
  /**
   * The message ID for the message that will be used if an error occurs while
   * trying to write the new schema files, but the server was able to properly
   * clean up after itself.  This takes a single argument,  which is a string
   * representation of the exception that was caught.
   */
  public static final int MSGID_SCHEMA_MODIFY_CANNOT_WRITE_NEW_FILES_RESTORED =
       CATEGORY_MASK_BACKEND | SEVERITY_MASK_MILD_ERROR | 253;
  /**
   * The message ID for the message that will be used if an error occurs while
   * trying to write the new schema files, and the server was not able to
   * properly clean up after itself.  This takes a single argument, which is a
   * string representation of the exception that was caught.
   */
  public static final int
       MSGID_SCHEMA_MODIFY_CANNOT_WRITE_NEW_FILES_NOT_RESTORED =
            CATEGORY_MASK_BACKEND | SEVERITY_MASK_MILD_ERROR | 254;
  /**
   * The message ID for the message that will be used if an attempt to remove
   * an attribute type from the schema fails because there is no such attribute
   * type defined.  This takes a single argument, which is the name or OID of
   * the attribute type to remove.
   */
  public static final int MSGID_SCHEMA_MODIFY_REMOVE_NO_SUCH_ATTRIBUTE_TYPE =
            CATEGORY_MASK_BACKEND | SEVERITY_MASK_MILD_ERROR | 255;
  /**
   * The message ID for the message that will be used if an attempt to remove
   * an attribute type from the schema fails because it is the superior type for
   * another attribute type.  This takes two arguments, which are the name or
   * OID of the attribute type to remove, and the name or OID of the subordinate
   * attribute type.
   */
  public static final int MSGID_SCHEMA_MODIFY_REMOVE_AT_SUPERIOR_TYPE =
            CATEGORY_MASK_BACKEND | SEVERITY_MASK_MILD_ERROR | 256;
  /**
   * The message ID for the message that will be used if an attempt to remove
   * an attribute type from the schema fails because the attribute type is
   * referenced by an objectclass.  This takes two arguments, which are the name
   * or OID of the attribute type and the name or OID of the objectclass.
   */
  public static final int MSGID_SCHEMA_MODIFY_REMOVE_AT_IN_OC =
            CATEGORY_MASK_BACKEND | SEVERITY_MASK_MILD_ERROR | 257;
  /**
   * The message ID for the message that will be used if an attempt to remove
   * an attribute type from the schema fails because the attribute type is
   * referenced by a name form.  This takes two arguments, which are the name or
   * OID of the attribute type and the name or OID of the name form.
   */
  public static final int MSGID_SCHEMA_MODIFY_REMOVE_AT_IN_NF =
            CATEGORY_MASK_BACKEND | SEVERITY_MASK_MILD_ERROR | 258;
  /**
   * The message ID for the message that will be used if an attempt to remove
   * an attribute type from the schema fails because the attribute type is
   * referenced by a DIT content rule.  This takes two arguments, which are the
   * name or OID of the attribute type and the name of the DIT content rule.
   */
  public static final int MSGID_SCHEMA_MODIFY_REMOVE_AT_IN_DCR =
            CATEGORY_MASK_BACKEND | SEVERITY_MASK_MILD_ERROR | 259;
  /**
   * The message ID for the message that will be used if an attempt to remove
   * an attribute type from the schema fails because the attribute type is
   * referenced by a matching rule use.  This takes two arguments, which are the
   * name or OID of the attribute type and the name of the matching rule use.
   */
  public static final int MSGID_SCHEMA_MODIFY_REMOVE_AT_IN_MR_USE =
            CATEGORY_MASK_BACKEND | SEVERITY_MASK_MILD_ERROR | 260;
  /**
   * The message ID for the message that will be used if an attempt to remove
   * an objectclass from the schema fails because there is no such objectclass
   * defined.  This takes a single argument, which is the name or OID of the
   * objectclass to remove.
   */
  public static final int MSGID_SCHEMA_MODIFY_REMOVE_NO_SUCH_OBJECTCLASS =
            CATEGORY_MASK_BACKEND | SEVERITY_MASK_MILD_ERROR | 261;
  /**
   * The message ID for the message that will be used if an attempt to remove
   * an objectclass from the schema fails because it is the superior class for
   * another objectclass.  This takes two arguments, which are the name or OID
   * of the objectclass to remove, and the name or OID of the subordinate
   * objectclass.
   */
  public static final int MSGID_SCHEMA_MODIFY_REMOVE_OC_SUPERIOR_CLASS =
            CATEGORY_MASK_BACKEND | SEVERITY_MASK_MILD_ERROR | 262;
  /**
   * The message ID for the message that will be used if an attempt to remove
   * an objectclass from the schema fails because the objectclass is referenced
   * by a name form.  This takes two arguments, which are the name or OID of the
   * objectclass and the name or OID of the name form.
   */
  public static final int MSGID_SCHEMA_MODIFY_REMOVE_OC_IN_NF =
            CATEGORY_MASK_BACKEND | SEVERITY_MASK_MILD_ERROR | 263;
  /**
   * The message ID for the message that will be used if an attempt to remove
   * an objectclass from the schema fails because the objectclass is referenced
   * by a DIT content rule.  This takes two arguments, which are the name or OID
   * of the objectclass and the name of the DIT content rule.
   */
  public static final int MSGID_SCHEMA_MODIFY_REMOVE_OC_IN_DCR =
            CATEGORY_MASK_BACKEND | SEVERITY_MASK_MILD_ERROR | 264;
  /**
   * The message ID for the message that will be used if an attempt to remove
   * a name form from the schema fails because there is no such name form
   * defined.  This takes a single argument, which is the name or OID of the
   * name form to remove.
   */
  public static final int MSGID_SCHEMA_MODIFY_REMOVE_NO_SUCH_NAME_FORM =
            CATEGORY_MASK_BACKEND | SEVERITY_MASK_MILD_ERROR | 265;
  /**
   * The message ID for the message that will be used if an attempt to remove
   * a name form from the schema fails because the name form is referenced by a
   * DIT structure rule.  This takes two arguments, which are the name or OID
   * of the name form and the name or rule ID of the DIT structure rule.
   */
  public static final int MSGID_SCHEMA_MODIFY_REMOVE_NF_IN_DSR =
            CATEGORY_MASK_BACKEND | SEVERITY_MASK_MILD_ERROR | 266;
  /**
   * The message ID for the message that will be used if an attempt to remove
   * a DIT content rule from the schema fails because there is no such DIT
   * content rule defined.  This takes a single argument, which is the name of
   * the DIT content rule to remove.
   */
  public static final int MSGID_SCHEMA_MODIFY_REMOVE_NO_SUCH_DCR =
            CATEGORY_MASK_BACKEND | SEVERITY_MASK_MILD_ERROR | 267;
  /**
   * The message ID for the message that will be used if an attempt to remove
   * a DIT structure rule from the schema fails because there is no such DIT
   * structure rule defined.  This takes a single argument, which is the name or
   * rule ID of the DIT structure rule to remove.
   */
  public static final int MSGID_SCHEMA_MODIFY_REMOVE_NO_SUCH_DSR =
            CATEGORY_MASK_BACKEND | SEVERITY_MASK_MILD_ERROR | 268;
  /**
   * The message ID for the message that will be used if an attempt to remove
   * a DIT structure rule from the schema fails because it is the superior rule
   * for another DIT structure rule.  This takes two arguments, which are the
   * name or rule ID of the DIT structure rule to remove, and the name or rule
   * ID of the subordinate rule.
   */
  public static final int MSGID_SCHEMA_MODIFY_REMOVE_DSR_SUPERIOR_RULE =
            CATEGORY_MASK_BACKEND | SEVERITY_MASK_MILD_ERROR | 269;
  /**
   * The message ID for the message that will be used if an attempt to remove
   * a matching rule use from the schema fails because there is no such matching
   * rule use defined.  This takes a single argument, which is the name of the
   * matching rule use to remove.
   */
  public static final int MSGID_SCHEMA_MODIFY_REMOVE_NO_SUCH_MR_USE =
            CATEGORY_MASK_BACKEND | SEVERITY_MASK_MILD_ERROR | 270;
  /**
   * The message ID for the message that will be used if an attempt is made to
   * add a new name form that references an objectclass that is not structural.
   * This takes two arguments, which are the name or OID of the new name form
   * and the name or OID of the objectclass.
   */
  public static final int MSGID_SCHEMA_MODIFY_NF_OC_NOT_STRUCTURAL =
       CATEGORY_MASK_BACKEND | SEVERITY_MASK_MILD_ERROR | 271;
  /**
   * The message ID for the message that will be used if an attempt is made to
   * add a new DIT content rule that references an objectclass that is not
   * structural.  This takes two arguments, which are the name of the new DIT
   * content rule and the name or OID of the objectclass.
   */
  public static final int MSGID_SCHEMA_MODIFY_DCR_OC_NOT_STRUCTURAL =
       CATEGORY_MASK_BACKEND | SEVERITY_MASK_MILD_ERROR | 272;
  /**
   * The message ID for the message that will be used if an attempt is made to
   * add a new name form that references a structural objectclass which is
   * already referenced by an existing name form.  This takes three arguments,
   * which are the name or OID of the new name form, the name or OID of the
   * structural objectclass, and the name or OID of the conflicting name form.
   */
  public static final int
       MSGID_SCHEMA_MODIFY_STRUCTURAL_OC_CONFLICT_FOR_ADD_NF =
            CATEGORY_MASK_BACKEND | SEVERITY_MASK_MILD_ERROR | 273;
  /**
   * Associates a set of generic messages with the message IDs defined in this
   * class.
   */
@@ -2609,12 +3197,9 @@
    registerMessage(MSGID_SCHEMA_DELETE_MODTYPE_NOT_SUPPORTED,
                    "The schema backend does not currently support removing " +
                    "existing schema elements.");
    // FIXME -- Change the below message once we support removing schema
    // elements.
    registerMessage(MSGID_SCHEMA_INVALID_MODIFICATION_TYPE,
                    "The schema backend does not support the %s modification " +
                    "type.  It is currently only possible to add new schema " +
                    "elements.");
                    "type.");
    registerMessage(MSGID_SCHEMA_MODIFY_UNSUPPORTED_ATTRIBUTE_TYPE,
                    "The schema backend does not support the modification of " +
                    "the %s attribute type.  Only attribute types, object " +
@@ -2630,6 +3215,21 @@
    registerMessage(MSGID_SCHEMA_MODIFY_CANNOT_DECODE_OBJECTCLASS,
                    "An error occurred while attempting to decode the object " +
                    "class \"%s\":  %s.");
    registerMessage(MSGID_SCHEMA_MODIFY_CANNOT_DECODE_NAME_FORM,
                    "An error occurred while attempting to decode the name " +
                    "form \"%s\":  %s.");
    registerMessage(MSGID_SCHEMA_MODIFY_CANNOT_DECODE_DCR,
                    "An error occurred while attempting to decode the DIT " +
                    "content rule \"%s\":  %s.");
    registerMessage(MSGID_SCHEMA_MODIFY_CANNOT_DECODE_DSR,
                    "An error occurred while attempting to decode the DIT " +
                    "structure rule \"%s\":  %s.");
    registerMessage(MSGID_SCHEMA_MODIFY_CANNOT_DECODE_MR_USE,
                    "An error occurred while attempting to decode the " +
                    "matching rule use \"%s\":  %s.");
    registerMessage(MSGID_SCHEMA_MODIFY_DELETE_NO_VALUES,
                    "The server will not allow removing all values for the " +
                    "%s attribute type in the server schema.");
    registerMessage(MSGID_SCHEMA_MODIFY_UNDEFINED_SUPERIOR_OBJECTCLASS,
                    "Unable to add objectclass %s because its superior " +
                    "class of %s is not defined in the server schema.");
@@ -2648,7 +3248,7 @@
                    "of schema file %s:  %s.");
    registerMessage(MSGID_SCHEMA_MODIFY_CANNOT_WRITE_NEW_SCHEMA,
                    "An error occurred while attepting to write the updated " +
                    "schema file %s:  %s.");
                    "schema:  %s.");
    registerMessage(MSGID_SCHEMA_MODIFY_DN_NOT_SUPPORTED,
                    "Unwilling to rename entry \"%s\" because modify DN " +
                    "operations are not supported in the schema backend.");
@@ -2710,6 +3310,188 @@
                    "An error occurred while attempting to update the backup " +
                    "descriptor file %s with information about the schema " +
                    "backup:  %s.");
    registerMessage(MSGID_SCHEMA_MODIFY_MULTIPLE_CONFLICTS_FOR_ADD_ATTRTYPE,
                    "Unable to add attribute type %s because it conflicts " +
                    "with multiple existing attribute types (%s and " +
                    "%s).");
    registerMessage(MSGID_SCHEMA_MODIFY_UNDEFINED_SUPERIOR_ATTRIBUTE_TYPE,
                    "Unable to add attribute type %s because it references " +
                    "superior attribute type %s which is not defined in the " +
                    "server schema.");
    registerMessage(MSGID_SCHEMA_MODIFY_MULTIPLE_CONFLICTS_FOR_ADD_OBJECTCLASS,
                    "Unable to add objectclass %s because it conflicts with " +
                    "multiple existing objectclasses (%s and %s).");
    registerMessage(MSGID_SCHEMA_MODIFY_MULTIPLE_CONFLICTS_FOR_ADD_NAME_FORM,
                    "Unable to add name form %s because it conflicts with " +
                    "multiple existing name forms (%s and %s).");
    registerMessage(MSGID_SCHEMA_MODIFY_NF_UNDEFINED_STRUCTURAL_OC,
                    "Unable to add name form %s because it references " +
                    "structural objectclass %s which is not defined in the " +
                    "server schema.");
    registerMessage(MSGID_SCHEMA_MODIFY_NF_OC_NOT_STRUCTURAL,
                    "Unable to add name form %s because it references " +
                    "objectclass %s which is defined in the server schema " +
                    "but is not a structural objectclass.");
    registerMessage(MSGID_SCHEMA_MODIFY_STRUCTURAL_OC_CONFLICT_FOR_ADD_NF,
                    "Unable to add name form %s because it references " +
                    "structural objectclass %s which is already associated " +
                    "with another name form %s.");
    registerMessage(MSGID_SCHEMA_MODIFY_NF_UNDEFINED_REQUIRED_ATTR,
                    "Unable to add name form %s because it references " +
                    "required attribute type %s which is not defined in the " +
                    "server schema.");
    registerMessage(MSGID_SCHEMA_MODIFY_NF_UNDEFINED_OPTIONAL_ATTR,
                    "Unable to add name form %s because it references " +
                    "optional attribute type %s which is not defined in the " +
                    "server schema.");
    registerMessage(MSGID_SCHEMA_MODIFY_MULTIPLE_CONFLICTS_FOR_ADD_DCR,
                    "Unable to add DIT content rule %s because it conflicts " +
                    "with multiple existing DIT content rules (%s and %s).");
    registerMessage(MSGID_SCHEMA_MODIFY_STRUCTURAL_OC_CONFLICT_FOR_ADD_DCR,
                    "Unable to add DIT content rule %s because it " +
                    "references structural objectclass %s which is already " +
                    "associated with another DIT content rule %s.");
    registerMessage(MSGID_SCHEMA_MODIFY_DCR_UNDEFINED_STRUCTURAL_OC,
                    "Unable to add DIT content rule %s because it " +
                    "references structural objectclass %s which is not " +
                    "defined in the server schema.");
    registerMessage(MSGID_SCHEMA_MODIFY_DCR_OC_NOT_STRUCTURAL,
                    "Unable to add DIT content rule %s because it " +
                    "references structural objectclass %s which is defined " +
                    "in the server schema but is not structural.");
    registerMessage(MSGID_SCHEMA_MODIFY_DCR_UNDEFINED_AUXILIARY_OC,
                    "Unable to add DIT content rule %s because it " +
                    "references auxiliary objectclass %s which is not " +
                    "defined in the server schema.");
    registerMessage(MSGID_SCHEMA_MODIFY_DCR_UNDEFINED_REQUIRED_ATTR,
                    "Unable to add DIT content rule %s because it " +
                    "references required attribute type %s which is not " +
                    "defined in the server schema.");
    registerMessage(MSGID_SCHEMA_MODIFY_DCR_UNDEFINED_OPTIONAL_ATTR,
                    "Unable to add DIT content rule %s because it " +
                    "references optional attribute type %s which is not " +
                    "defined in the server schema.");
    registerMessage(MSGID_SCHEMA_MODIFY_DCR_UNDEFINED_PROHIBITED_ATTR,
                    "Unable to add DIT content rule %s because it " +
                    "references prohibited attribute type %s which is not " +
                    "defined in the server schema.");
    registerMessage(MSGID_SCHEMA_MODIFY_MULTIPLE_CONFLICTS_FOR_ADD_DSR,
                    "Unable to add DIT structure rule %s because it " +
                    "conflicts with multiple existing DIT structure rules " +
                    "(%s and %s).");
    registerMessage(MSGID_SCHEMA_MODIFY_NAME_FORM_CONFLICT_FOR_ADD_DSR,
                    "Unable to add DIT structure rule %s because it " +
                    "references name form %s which is already associated " +
                    "with another DIT structure rule %s.");
    registerMessage(MSGID_SCHEMA_MODIFY_DSR_UNDEFINED_NAME_FORM,
                    "Unable to add DIT structure rule %s because it " +
                    "references name form %s which is not defined in the " +
                    "server schema.");
    registerMessage(MSGID_SCHEMA_MODIFY_MULTIPLE_CONFLICTS_FOR_ADD_MR_USE,
                    "Unable to add matching rule use %s because it " +
                    "conflicts with multiple existing matching rule uses " +
                    "(%s and %s).");
    registerMessage(MSGID_SCHEMA_MODIFY_MR_CONFLICT_FOR_ADD_MR_USE,
                    "Unable to add matching rule use %s because it " +
                    "references matching rule %s which is already associated " +
                    "with another matching rule use %s.");
    registerMessage(MSGID_SCHEMA_MODIFY_MRU_UNDEFINED_ATTR,
                    "Unable to add matching rule use %s because it " +
                    "references attribute type %s which is not defined in " +
                    "the server schema.");
    registerMessage(MSGID_SCHEMA_MODIFY_CIRCULAR_REFERENCE_AT,
                    "Circular reference detected for attribute type %s in " +
                    "which the superior type chain references the " +
                    "attribute type itself.");
    registerMessage(MSGID_SCHEMA_MODIFY_CIRCULAR_REFERENCE_OC,
                    "Circular reference detected for objectclass %s in which " +
                    "the superior class chain references the objectclass " +
                    "itself.");
    registerMessage(MSGID_SCHEMA_MODIFY_CIRCULAR_REFERENCE_DSR,
                    "Circular reference detected for DIT structure rule %s " +
                    "in which the superior rule chain references the DIT " +
                    "structure rule itself.");
    registerMessage(MSGID_SCHEMA_MODIFY_CANNOT_WRITE_ORIG_FILES_CLEANED,
                    "An error occurred while attempting to create copies " +
                    "of the existing schema files before applying the " +
                    "updates:  %s.  The server was able to restore the " +
                    "original schema configuration, so no additional " +
                    "cleanup should be required.");
    registerMessage(MSGID_SCHEMA_MODIFY_CANNOT_WRITE_ORIG_FILES_NOT_CLEANED,
                    "An error occurred while attempting to create copies " +
                    "of the existing schema files before applying the " +
                    "updates:  %s.  A problem also occurred when attempting " +
                    "to restore the original schema configuration, so the " +
                    "server may be left in an inconsistent state and could " +
                    "require manual cleanup.");
    registerMessage(MSGID_SCHEMA_MODIFY_CANNOT_WRITE_NEW_FILES_RESTORED,
                    "An error occurred while attempting to write new " +
                    "versions of the server schema files:  %s.   The server " +
                    "was able to restore the original schema configuration, " +
                    "so no additional cleanup should be required.");
    registerMessage(MSGID_SCHEMA_MODIFY_CANNOT_WRITE_NEW_FILES_NOT_RESTORED,
                    "An error occrred while attempting to write new " +
                    "versions of the server schema files:  %s.  A problem " +
                    "also occured when attempting to restore the original " +
                    "schema configuration, so the server may be left in an " +
                    "inconsistent state and could require manual cleanup.");
    registerMessage(MSGID_SCHEMA_MODIFY_REMOVE_NO_SUCH_ATTRIBUTE_TYPE,
                    "Unable to remove attribute type %s from the server " +
                    "schema because no such attribute type is defined.");
    registerMessage(MSGID_SCHEMA_MODIFY_REMOVE_AT_SUPERIOR_TYPE,
                    "Unable to remove attribute type %s from the server " +
                    "schema because it is referenced as the superior type " +
                    "for attribute type %s.");
    registerMessage(MSGID_SCHEMA_MODIFY_REMOVE_AT_IN_OC,
                    "Unable to remove attribute type %s from the server " +
                    "schema because it is referenced as a required or " +
                    "optional attribute type in objectclass %s.");
    registerMessage(MSGID_SCHEMA_MODIFY_REMOVE_AT_IN_NF,
                    "Unable to remove attribute type %s from the server " +
                    "schema because it is referenced as a required or " +
                    "optional attribute type in name form %s.");
    registerMessage(MSGID_SCHEMA_MODIFY_REMOVE_AT_IN_DCR,
                    "Unable to remove attribute type %s from the server " +
                    "schema because it is referenced as a required, " +
                    "optional, or prohibited attribute type in DIT content " +
                    "rule %s.");
    registerMessage(MSGID_SCHEMA_MODIFY_REMOVE_AT_IN_MR_USE,
                    "Unable to remove attribute type %s from the server " +
                    "schema because it is referenced by matching rule use %s");
    registerMessage(MSGID_SCHEMA_MODIFY_REMOVE_NO_SUCH_OBJECTCLASS,
                    "Unable to remove objectclass %s from the server schema " +
                    "because no such objectclass is defined.");
    registerMessage(MSGID_SCHEMA_MODIFY_REMOVE_OC_SUPERIOR_CLASS,
                    "Unable to remove objectclass %s from the server schema " +
                    "because it is referenced as the superior class for " +
                    "objectclass %s.");
    registerMessage(MSGID_SCHEMA_MODIFY_REMOVE_OC_IN_NF,
                    "Unable to remove objectclass %s from the server schema " +
                    "because it is referenced as the structural class for " +
                    "name form %s.");
    registerMessage(MSGID_SCHEMA_MODIFY_REMOVE_OC_IN_DCR,
                    "Unable to remove objectclass %s from the server schema " +
                    "because it is referenced as a structural or auxiliary " +
                    "class for DIT content rule %s.");
    registerMessage(MSGID_SCHEMA_MODIFY_REMOVE_NO_SUCH_NAME_FORM,
                    "Unable to remove name form %s from the server schema " +
                    "because no such name form is defined.");
    registerMessage(MSGID_SCHEMA_MODIFY_REMOVE_NF_IN_DSR,
                    "Unable to remove name form %s from the server schema " +
                    "because it is referenced by DIT structure rule %s.");
    registerMessage(MSGID_SCHEMA_MODIFY_REMOVE_NO_SUCH_DCR,
                    "Unable to remove DIT content rule %s from the server " +
                    "schema because no such DIT content rule is defined.");
    registerMessage(MSGID_SCHEMA_MODIFY_REMOVE_NO_SUCH_DSR,
                    "Unable to remove DIT structure rule %s from the server " +
                    "schema because no such DIT structure rule is defined.");
    registerMessage(MSGID_SCHEMA_MODIFY_REMOVE_DSR_SUPERIOR_RULE,
                    "Unable to remove DIT structure rule %s from the server " +
                    "schema because it is referenced as a superior rule for " +
                    "DIT structure rule %s.");
    registerMessage(MSGID_SCHEMA_MODIFY_REMOVE_NO_SUCH_MR_USE,
                    "Unable to remove matching rule use %s from the server " +
                    "schema because no such matching rule use is defined.");
    registerMessage(MSGID_SCHEMA_RESTORE_NO_SUCH_BACKUP,
opendj-sdk/opends/src/server/org/opends/server/messages/CoreMessages.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2006 Sun Microsystems, Inc.
 *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
 */
package org.opends.server.messages;
@@ -6057,6 +6057,16 @@
       CATEGORY_MASK_CORE | SEVERITY_MASK_SEVERE_WARNING | 578;
  /**
   * The message ID for the message that will be used if a circular reference is
   * detected when attempting to rebuild schema element dependencies.  This
   * takes a single argument, which is the definition string for the schema
   * element that triggered the circular reference error.
   */
  public static final int MSGID_SCHEMA_CIRCULAR_DEPENDENCY_REFERENCE =
       CATEGORY_MASK_CORE | SEVERITY_MASK_MILD_ERROR | 579;
  /**
   * Associates a set of generic messages with the message IDs defined
@@ -6751,6 +6761,11 @@
                    "Unable to register name form %s with the server schema " +
                    "because its name %s conflicts with the name for an " +
                    "existing name form %s.");
    registerMessage(MSGID_SCHEMA_CIRCULAR_DEPENDENCY_REFERENCE,
                    "Unable to update the schema element with definition " +
                    "\"%s\" because a circular reference was identified " +
                    "when attempting to rebuild other schema elements " +
                    "dependent upon it.");
    registerMessage(MSGID_ADD_OP_INVALID_SYNTAX,
opendj-sdk/opends/src/server/org/opends/server/plugins/EntryUUIDPlugin.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2006 Sun Microsystems, Inc.
 *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
 */
package org.opends.server.plugins;
@@ -110,9 +110,15 @@
                                                        false);
    if (at == null)
    {
      at = new AttributeType(ENTRYUUID, Collections.singleton(ENTRYUUID),
                             ENTRYUUID, null, null,
                             DirectoryConfig.getDefaultAttributeSyntax(),
      String definition =
           "( 1.3.6.1.1.16.4 NAME 'entryUUID' DESC 'UUID of the entry' " +
           "EQUALITY uuidMatch ORDERING uuidOrderingMatch " +
           "SYNTAX 1.3.6.1.1.16.1 SINGLE-VALUE NO-USER-MODIFICATION " +
           "USAGE directoryOperation X-ORIGIN 'RFC 4530' )";
      at = new AttributeType(definition, ENTRYUUID,
                             Collections.singleton(ENTRYUUID), ENTRYUUID, null,
                             null, DirectoryConfig.getDefaultAttributeSyntax(),
                             AttributeUsage.DIRECTORY_OPERATION, false, true,
                             false, true);
    }
opendj-sdk/opends/src/server/org/opends/server/schema/AttributeTypeSyntax.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2006 Sun Microsystems, Inc.
 *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
 */
package org.opends.server.schema;
@@ -926,12 +926,12 @@
    }
    return new AttributeType(primaryName, typeNames, oid, description,
                             superiorType, syntax, approximateMatchingRule,
                             equalityMatchingRule, orderingMatchingRule,
                             substringMatchingRule, attributeUsage,
                             isCollective, isNoUserModification, isObsolete,
                             isSingleValue, extraProperties);
    return new AttributeType(value.stringValue(), primaryName, typeNames, oid,
                             description, superiorType, syntax,
                             approximateMatchingRule, equalityMatchingRule,
                             orderingMatchingRule, substringMatchingRule,
                             attributeUsage, isCollective, isNoUserModification,
                             isObsolete, isSingleValue, extraProperties);
  }
opendj-sdk/opends/src/server/org/opends/server/schema/DITContentRuleSyntax.java
@@ -22,16 +22,16 @@
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2006 Sun Microsystems, Inc.
 *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
 */
package org.opends.server.schema;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.List;
import org.opends.server.api.ApproximateMatchingRule;
import org.opends.server.api.AttributeSyntax;
@@ -503,20 +503,19 @@
    // out what it is and how to treat what comes after it, then repeat until
    // we get to the end of the value.  But before we start, set default values
    // for everything else we might need to know.
    ConcurrentHashMap<String,String> names =
         new ConcurrentHashMap<String,String>();
    LinkedHashMap<String,String> names = new LinkedHashMap<String,String>();
    String description = null;
    boolean isObsolete = false;
    CopyOnWriteArraySet<ObjectClass> auxiliaryClasses =
         new CopyOnWriteArraySet<ObjectClass>();
    CopyOnWriteArraySet<AttributeType> requiredAttributes =
         new CopyOnWriteArraySet<AttributeType>();
    CopyOnWriteArraySet<AttributeType> optionalAttributes =
         new CopyOnWriteArraySet<AttributeType>();
    CopyOnWriteArraySet<AttributeType> prohibitedAttributes =
         new CopyOnWriteArraySet<AttributeType>();
    ConcurrentHashMap<String,CopyOnWriteArrayList<String>> extraProperties =
         new ConcurrentHashMap<String,CopyOnWriteArrayList<String>>();
    LinkedHashSet<ObjectClass> auxiliaryClasses =
         new LinkedHashSet<ObjectClass>();
    LinkedHashSet<AttributeType> requiredAttributes =
         new LinkedHashSet<AttributeType>();
    LinkedHashSet<AttributeType> optionalAttributes =
         new LinkedHashSet<AttributeType>();
    LinkedHashSet<AttributeType> prohibitedAttributes =
         new LinkedHashSet<AttributeType>();
    LinkedHashMap<String,List<String>> extraProperties =
         new LinkedHashMap<String,List<String>>();
    while (true)
@@ -943,16 +942,15 @@
        // either a single value in single quotes or an open parenthesis
        // followed by one or more values in single quotes separated by spaces
        // followed by a close parenthesis.
        CopyOnWriteArrayList<String> valueList =
             new CopyOnWriteArrayList<String>();
        LinkedList<String> valueList = new LinkedList<String>();
        pos = readExtraParameterValues(valueStr, valueList, pos);
        extraProperties.put(tokenName, valueList);
      }
    }
    return new DITContentRule(structuralClass, names, description,
                              auxiliaryClasses, requiredAttributes,
    return new DITContentRule(value.stringValue(), structuralClass, names,
                              description, auxiliaryClasses, requiredAttributes,
                              optionalAttributes, prohibitedAttributes,
                              isObsolete, extraProperties);
  }
@@ -1374,7 +1372,8 @@
   *                              the value.
   */
  private static int readExtraParameterValues(String valueStr,
                          CopyOnWriteArrayList<String> valueList, int startPos)
                                              List<String> valueList,
                                              int startPos)
          throws DirectoryException
  {
    assert debugEnter(CLASS_NAME, "readExtraParameterValues",
opendj-sdk/opends/src/server/org/opends/server/schema/DITStructureRuleSyntax.java
@@ -22,16 +22,16 @@
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2006 Sun Microsystems, Inc.
 *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
 */
package org.opends.server.schema;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.List;
import org.opends.server.api.ApproximateMatchingRule;
import org.opends.server.api.AttributeSyntax;
@@ -281,7 +281,7 @@
    // acceptable.
    try
    {
      decodeDITStructureRule(value, DirectoryServer.getSchema());
      decodeDITStructureRule(value, DirectoryServer.getSchema(), true);
      return true;
    }
    catch (DirectoryException de)
@@ -302,10 +302,16 @@
   * should not be in order to allow the desired capitalization to be
   * preserved).
   *
   * @param  value   The ASN.1 octet string 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  value                 The ASN.1 octet string 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 name form and/or superior rules
   *                               which are not defined in the server schema.
   *                               This should only be true when called by
   *                               {@code valueIsAcceptable}.
   *
   * @return  The decoded DIT structure rule definition.
   *
@@ -313,7 +319,8 @@
   *                              DIT structure rule definition.
   */
  public static DITStructureRule decodeDITStructureRule(ByteString value,
                                                        Schema schema)
                                      Schema schema,
                                      boolean allowUnknownElements)
         throws DirectoryException
  {
    assert debugEnter(CLASS_NAME, "decodeDITStructureRule",
@@ -428,14 +435,14 @@
    // out what it is and how to treat what comes after it, then repeat until
    // we get to the end of the value.  But before we start, set default values
    // for everything else we might need to know.
    ConcurrentHashMap<String,String> names =
         new ConcurrentHashMap<String,String>();
    LinkedHashMap<String,String> names = new LinkedHashMap<String,String>();
    String description = null;
    boolean isObsolete = false;
    NameForm nameForm = null;
    CopyOnWriteArraySet<DITStructureRule> superiorRules = null;
    ConcurrentHashMap<String,CopyOnWriteArrayList<String>> extraProperties =
         new ConcurrentHashMap<String,CopyOnWriteArrayList<String>>();
    boolean nameFormGiven = false;
    LinkedHashSet<DITStructureRule> superiorRules = null;
    LinkedHashMap<String,List<String>> extraProperties =
         new LinkedHashMap<String,List<String>>();
    while (true)
@@ -533,8 +540,9 @@
        StringBuilder woidBuffer = new StringBuilder();
        pos = readWOID(lowerStr, woidBuffer, pos);
        nameFormGiven = true;
        nameForm = schema.getNameForm(woidBuffer.toString());
        if (nameForm == null)
        if ((nameForm == null) && (! allowUnknownElements))
        {
          int    msgID   = MSGID_ATTR_SYNTAX_DSR_UNKNOWN_NAME_FORM;
          String message = getMessage(msgID, valueStr, woidBuffer.toString());
@@ -605,10 +613,14 @@
                 schema.getDITStructureRule(supRuleID);
            if (superiorRule == null)
            {
              int msgID = MSGID_ATTR_SYNTAX_DSR_UNKNOWN_RULE_ID;
              String message = getMessage(msgID, valueStr, supRuleID);
              throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
                                           message, msgID);
              if (! allowUnknownElements)
              {
                int    msgID   = MSGID_ATTR_SYNTAX_DSR_UNKNOWN_RULE_ID;
                String message = getMessage(msgID, valueStr, supRuleID);
                throw new DirectoryException(
                               ResultCode.INVALID_ATTRIBUTE_SYNTAX, message,
                               msgID);
              }
            }
            else
            {
@@ -698,10 +710,13 @@
          DITStructureRule superiorRule = schema.getDITStructureRule(supRuleID);
          if (superiorRule == null)
          {
            int msgID = MSGID_ATTR_SYNTAX_DSR_UNKNOWN_RULE_ID;
            String message = getMessage(msgID, valueStr, supRuleID);
            throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
                                         message, msgID);
            if (! allowUnknownElements)
            {
              int    msgID   = MSGID_ATTR_SYNTAX_DSR_UNKNOWN_RULE_ID;
              String message = getMessage(msgID, valueStr, supRuleID);
              throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
                                           message, msgID);
            }
          }
          else
          {
@@ -724,7 +739,7 @@
          }
        }
        superiorRules = new CopyOnWriteArraySet<DITStructureRule>(superiorList);
        superiorRules = new LinkedHashSet<DITStructureRule>(superiorList);
      }
      else
      {
@@ -732,15 +747,15 @@
        // either a single value in single quotes or an open parenthesis
        // followed by one or more values in single quotes separated by spaces
        // followed by a close parenthesis.
        CopyOnWriteArrayList<String> valueList =
             new CopyOnWriteArrayList<String>();
        LinkedList<String> valueList =
             new LinkedList<String>();
        pos = readExtraParameterValues(valueStr, valueList, pos);
        extraProperties.put(tokenName, valueList);
      }
    }
    if (nameForm == null)
    if ((nameForm == null) && (! nameFormGiven))
    {
      int    msgID   = MSGID_ATTR_SYNTAX_DSR_NO_NAME_FORM;
      String message = getMessage(msgID, valueStr);
@@ -749,8 +764,9 @@
    }
    return new DITStructureRule(names, ruleID, description, isObsolete,
                                nameForm, superiorRules, extraProperties);
    return new DITStructureRule(value.stringValue(), names, ruleID, description,
                                isObsolete, nameForm, superiorRules,
                                extraProperties);
  }
@@ -1170,7 +1186,7 @@
   *                              the value.
   */
  private static int readExtraParameterValues(String valueStr,
                          CopyOnWriteArrayList<String> valueList, int startPos)
                          List<String> valueList, int startPos)
          throws DirectoryException
  {
    assert debugEnter(CLASS_NAME, "readExtraParameterValues",
opendj-sdk/opends/src/server/org/opends/server/schema/MatchingRuleUseSyntax.java
@@ -22,14 +22,16 @@
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2006 Sun Microsystems, Inc.
 *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
 */
package org.opends.server.schema;
import java.util.*;
import java.util.concurrent.*;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import org.opends.server.api.ApproximateMatchingRule;
import org.opends.server.api.AttributeSyntax;
@@ -490,13 +492,12 @@
    // out what it is and how to treat what comes after it, then repeat until
    // we get to the end of the value.  But before we start, set default values
    // for everything else we might need to know.
    ConcurrentHashMap<String,String> names =
         new ConcurrentHashMap<String,String>();
    LinkedHashMap<String,String> names = new LinkedHashMap<String,String>();
    String description = null;
    boolean isObsolete = false;
    CopyOnWriteArraySet<AttributeType> attributes = null;
    ConcurrentHashMap<String,CopyOnWriteArrayList<String>> extraProperties =
         new ConcurrentHashMap<String,CopyOnWriteArrayList<String>>();
    LinkedHashSet<AttributeType> attributes = null;
    LinkedHashMap<String,List<String>> extraProperties =
         new LinkedHashMap<String,List<String>>();
    while (true)
    {
@@ -664,7 +665,7 @@
          attrs.add(attr);
        }
        attributes = new CopyOnWriteArraySet<AttributeType>(attrs);
        attributes = new LinkedHashSet<AttributeType>(attrs);
      }
      else
      {
@@ -672,8 +673,7 @@
        // either a single value in single quotes or an open parenthesis
        // followed by one or more values in single quotes separated by spaces
        // followed by a close parenthesis.
        CopyOnWriteArrayList<String> valueList =
             new CopyOnWriteArrayList<String>();
        LinkedList<String> valueList = new LinkedList<String>();
        pos = readExtraParameterValues(valueStr, valueList, pos);
        extraProperties.put(tokenName, valueList);
      }
@@ -690,8 +690,9 @@
    }
    return new MatchingRuleUse(matchingRule, names, description, isObsolete,
                               attributes, extraProperties);
    return new MatchingRuleUse(value.stringValue(), matchingRule, names,
                               description, isObsolete, attributes,
                               extraProperties);
  }
@@ -1110,7 +1111,7 @@
   *                              the value.
   */
  private static int readExtraParameterValues(String valueStr,
                          CopyOnWriteArrayList<String> valueList, int startPos)
                          List<String> valueList, int startPos)
          throws DirectoryException
  {
    assert debugEnter(CLASS_NAME, "readExtraParameterValues",
opendj-sdk/opends/src/server/org/opends/server/schema/NameFormSyntax.java
@@ -22,16 +22,16 @@
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2006 Sun Microsystems, Inc.
 *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
 */
package org.opends.server.schema;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.List;
import org.opends.server.api.ApproximateMatchingRule;
import org.opends.server.api.AttributeSyntax;
@@ -478,17 +478,16 @@
    // out what it is and how to treat what comes after it, then repeat until
    // we get to the end of the value.  But before we start, set default values
    // for everything else we might need to know.
    ConcurrentHashMap<String,String> names =
         new ConcurrentHashMap<String,String>();
    LinkedHashMap<String,String> names = new LinkedHashMap<String,String>();
    String description = null;
    boolean isObsolete = false;
    ObjectClass structuralClass = null;
    CopyOnWriteArraySet<AttributeType> requiredAttributes =
         new CopyOnWriteArraySet<AttributeType>();
    CopyOnWriteArraySet<AttributeType> optionalAttributes =
         new CopyOnWriteArraySet<AttributeType>();
    ConcurrentHashMap<String,CopyOnWriteArrayList<String>> extraProperties =
         new ConcurrentHashMap<String,CopyOnWriteArrayList<String>>();
    LinkedHashSet<AttributeType> requiredAttributes =
         new LinkedHashSet<AttributeType>();
    LinkedHashSet<AttributeType> optionalAttributes =
         new LinkedHashSet<AttributeType>();
    LinkedHashMap<String,List<String>> extraProperties =
         new LinkedHashMap<String,List<String>>();
    while (true)
@@ -775,8 +774,7 @@
        // either a single value in single quotes or an open parenthesis
        // followed by one or more values in single quotes separated by spaces
        // followed by a close parenthesis.
        CopyOnWriteArrayList<String> valueList =
             new CopyOnWriteArrayList<String>();
        LinkedList<String> valueList = new LinkedList<String>();
        pos = readExtraParameterValues(valueStr, valueList, pos);
        extraProperties.put(tokenName, valueList);
      }
@@ -794,9 +792,9 @@
    }
    return new NameForm(names, oid, description, isObsolete, structuralClass,
                        requiredAttributes, optionalAttributes,
                        extraProperties);
    return new NameForm(value.stringValue(), names, oid, description,
                        isObsolete, structuralClass, requiredAttributes,
                        optionalAttributes, extraProperties);
  }
@@ -1215,7 +1213,7 @@
   *                              the value.
   */
  private static int readExtraParameterValues(String valueStr,
                          CopyOnWriteArrayList<String> valueList, int startPos)
                          List<String> valueList, int startPos)
          throws DirectoryException
  {
    assert debugEnter(CLASS_NAME, "readExtraParameterValues",
opendj-sdk/opends/src/server/org/opends/server/schema/ObjectClassSyntax.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2006 Sun Microsystems, Inc.
 *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
 */
package org.opends.server.schema;
@@ -807,9 +807,10 @@
    }
    return new ObjectClass(primaryName, names, oid, description, superiorClass,
                           requiredAttributes, optionalAttributes,
                           objectClassType, isObsolete, extraProperties);
    return new ObjectClass(value.stringValue(), primaryName, names, oid,
                           description, superiorClass, requiredAttributes,
                           optionalAttributes, objectClassType, isObsolete,
                           extraProperties);
  }
opendj-sdk/opends/src/server/org/opends/server/types/AttributeType.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2006 Sun Microsystems, Inc.
 *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
 */
package org.opends.server.types;
@@ -31,17 +31,20 @@
import java.util.Collection;
import java.util.List;
import java.util.Map;
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.core.DirectoryServer;
import org.opends.server.schema.AttributeTypeSyntax;
import static org.opends.server.loggers.Debug.*;
import static org.opends.server.messages.CoreMessages.*;
import static org.opends.server.messages.MessageHandler.*;
import static org.opends.server.util.ServerConstants.*;
import static org.opends.server.util.Validator.*;
@@ -60,7 +63,9 @@
 * ordering will be preserved when the associated fields are accessed
 * via their getters or via the {@link #toString()} methods.
 */
public final class AttributeType extends CommonSchemaElements
public final class AttributeType
       extends CommonSchemaElements
       implements SchemaFileElement
{
  /**
   * The fully-qualified name of this class for debugging purposes.
@@ -102,6 +107,9 @@
  // The ordering matching rule for this attribute type.
  private final OrderingMatchingRule orderingMatchingRule;
  // The definition string used to create this attribute type.
  private final String definition;
  // The substring matching rule for this attribute type.
  private final SubstringMatchingRule substringMatchingRule;
@@ -115,6 +123,9 @@
   * from the set of <code>names</code> will be used as the primary
   * name.
   *
   * @param definition
   *          The definition string used to create this attribute
   *          type.  It must not be {@code null}.
   * @param primaryName
   *          The primary name for this attribute type, or
   *          <code>null</code> if there is no primary name.
@@ -122,8 +133,8 @@
   *          The full set of names for this attribute type, or
   *          <code>null</code> if there are no names.
   * @param oid
   *          The OID for this attribute type (must not be
   *          <code>null</code>).
   *          The OID for this attribute type.  It must not be
   *          {@code null}.
   * @param description
   *          The description for the attribute type, or
   *          <code>null</code> if there is no description.
@@ -150,7 +161,7 @@
   *          Indicates whether this attribute type is declared
   *          "single-value".
   */
  public AttributeType(String primaryName,
  public AttributeType(String definition, String primaryName,
                       Collection<String> typeNames,
                       String oid, String description,
                       AttributeType superiorType,
@@ -160,7 +171,7 @@
                       boolean isNoUserModification,
                       boolean isObsolete, boolean isSingleValue)
  {
    this(primaryName, typeNames, oid, description,
    this(definition, primaryName, typeNames, oid, description,
        superiorType, syntax, null, null, null,
        null, attributeUsage, isCollective,
        isNoUserModification, isObsolete, isSingleValue, null);
@@ -176,6 +187,9 @@
   * from the set of <code>names</code> will be used as the primary
   * name.
   *
   * @param definition
   *          The definition string used to create this attribute
   *          type.  It must not be {@code null}.
   * @param primaryName
   *          The primary name for this attribute type, or
   *          <code>null</code> if there is no primary name.
@@ -183,8 +197,8 @@
   *          The full set of names for this attribute type, or
   *          <code>null</code> if there are no names.
   * @param oid
   *          The OID for this attribute type (must not be
   *          <code>null</code>).
   *          The OID for this attribute type.  It must not be
   *          {@code null}.
   * @param description
   *          The description for the attribute type, or
   *          <code>null</code> if there is no description.
@@ -225,10 +239,8 @@
   * @param extraProperties
   *          A set of extra properties for this attribute type, or
   *          <code>null</code> if there are no extra properties.
   * @throws NullPointerException
   *           If the provided OID was <code>null</code>.
   */
  public AttributeType(String primaryName,
  public AttributeType(String definition, String primaryName,
                       Collection<String> typeNames,
                       String oid, String description,
                       AttributeType superiorType,
@@ -243,12 +255,13 @@
                       boolean isNoUserModification,
                       boolean isObsolete, boolean isSingleValue,
                       Map<String,List<String>> extraProperties)
                       throws NullPointerException
  {
    super(primaryName, typeNames, oid, description, isObsolete,
        extraProperties);
    assert debugConstructor(CLASS_NAME,String.valueOf(primaryName),
    assert debugConstructor(CLASS_NAME,
                              String.valueOf(definition),
                              String.valueOf(primaryName),
                              String.valueOf(typeNames),
                              String.valueOf(oid),
                              String.valueOf(description),
@@ -265,6 +278,9 @@
                              String.valueOf(isSingleValue),
                              String.valueOf(extraProperties));
    ensureNotNull(definition, oid);
    this.definition   = definition;
    this.superiorType = superiorType;
    this.isCollective = isCollective;
    this.isNoUserModification = isNoUserModification;
@@ -352,6 +368,51 @@
  /**
   * Retrieves the definition string used to create this attribute
   * type.
   *
   * @return  The definition string used to create this attribute
   *          type.
   */
  public String getDefinition()
  {
    assert debugEnter(CLASS_NAME, "getDefinition");
    return definition;
  }
  /**
   * Creates a new instance of this attribute type based on the
   * definition string.  It will also preserve other state information
   * associated with this attribute type that is not included in the
   * definition string (e.g., the name of the schema file with which
   * it is associated).
   *
   * @return  The new instance of this attribute type based on the
   *          definition string.
   *
   * @throws  DirectoryException  If a problem occurs while attempting
   *                              to create a new attribute type
   *                              instance from the definition string.
   */
  public AttributeType recreateFromDefinition()
         throws DirectoryException
  {
    ByteString value  = ByteStringFactory.create(definition);
    Schema     schema = DirectoryServer.getSchema();
    AttributeType at =
         AttributeTypeSyntax.decodeAttributeType(value, schema);
    at.setSchemaFile(getSchemaFile());
    return at;
  }
  /**
   * Retrieves the superior type for this attribute type.
   *
   * @return  The superior type for this attribute type, or
opendj-sdk/opends/src/server/org/opends/server/types/CommonSchemaElements.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2006 Sun Microsystems, Inc.
 *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
 */
package org.opends.server.types;
@@ -32,10 +32,12 @@
import static org.opends.server.loggers.Debug.debugEnter;
import static org.opends.server.util.ServerConstants.*;
import static org.opends.server.util.StaticUtils.toLowerCase;
import static org.opends.server.util.Validator.*;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -59,6 +61,12 @@
 * Where ordered sets of names, or extra properties are provided, the
 * ordering will be preserved when the associated fields are accessed
 * via their getters or via the {@link #toString()} methods.
 * <p>
 * Note that these schema elements are not completely immutable, as
 * the set of extra properties for the schema element may be altered
 * after the element is created.  Among other things, this allows the
 * associated schema file to be edited so that an element created over
 * protocol may be associated with a particular schema file.
 */
public abstract class CommonSchemaElements {
  /**
@@ -316,10 +324,10 @@
  /**
   * Retrieves the path to the schema file that contains the
   * Retrieves the name of the schema file that contains the
   * definition for this schema definition.
   *
   * @return The path to the schema file that contains the definition
   * @return The name of the schema file that contains the definition
   *         for this schema definition, or <code>null</code> if it
   *         is not known or if it is not stored in any schema file.
   */
@@ -338,6 +346,25 @@
  /**
   * Specifies the name of the schema file that contains the
   * definition for this schema element.  If a schema file is already
   * defined in the set of extra properties, then it will be
   * overwritten.  If the provided schema file value is {@code null},
   * then any existing schema file definition will be removed.
   *
   * @param  schemaFile  The name of the schema file that contains the
   *                     definition for this schema element.
   */
  public final void setSchemaFile(String schemaFile) {
    assert debugEnter(CLASS_NAME, "setSchemaFile",
                      String.valueOf(schemaFile));
    setExtraProperty(SCHEMA_PROPERTY_FILENAME, schemaFile);
  }
  /**
   * Retrieves the description for this schema definition.
   *
   * @return The description for this schema definition, or
@@ -401,6 +428,72 @@
  /**
   * Sets the value for an "extra" property for this schema element.
   * If a property already exists with the specified name, then it
   * will be overwritten.  If the value is {@code null}, then any
   * existing property with the given name will be removed.
   *
   * @param  name   The name for the "extra" property.  It must not be
   *                {@code null}.
   * @param  value  The value for the "extra" property.  If it is
   *                {@code null}, then any existing definition will be
   *                removed.
   */
  public final void setExtraProperty(String name, String value) {
    assert debugEnter(CLASS_NAME, "setExtraProperty",
                      String.valueOf(name), String.valueOf(value));
    ensureNotNull(name);
    if (value == null)
    {
      extraProperties.remove(name);
    }
    else
    {
      LinkedList<String> values = new LinkedList<String>();
      values.add(value);
      extraProperties.put(name, values);
    }
  }
  /**
   * Sets the values for an "extra" property for this schema element.
   * If a property already exists with the specified name, then it
   * will be overwritten.  If the set of values is {@code null} or
   * empty, then any existing property with the given name will be
   * removed.
   *
   * @param  name    The name for the "extra" property.  It must not
   *                 be {@code null}.
   * @param  values  The set of values for the "extra" property.  If
   *                 it is {@code null} or empty, then any existing
   *                 definition will be removed.
   */
  public final void setExtraProperty(String name,
                                     List<String> values) {
    assert debugEnter(CLASS_NAME, "setExtraProperty",
                      String.valueOf(name), String.valueOf(values));
    ensureNotNull(name);
    if ((values == null) || values.isEmpty())
    {
      extraProperties.remove(name);
    }
    else
    {
      LinkedList<String> valuesCopy = new LinkedList<String>(values);
      extraProperties.put(name, valuesCopy);
    }
  }
  /**
   * Indicates whether the provided object is equal to this attribute
   * type. The object will be considered equal if it is an attribute
   * type with the same OID as the current type.
opendj-sdk/opends/src/server/org/opends/server/types/DITContentRule.java
@@ -22,16 +22,21 @@
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2006 Sun Microsystems, Inc.
 *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
 */
package org.opends.server.types;
import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.opends.server.schema.DITContentRuleSyntax;
import static org.opends.server.loggers.Debug.*;
import static org.opends.server.loggers.Error.*;
@@ -39,6 +44,7 @@
import static org.opends.server.messages.MessageHandler.*;
import static org.opends.server.util.ServerConstants.*;
import static org.opends.server.util.StaticUtils.*;
import static org.opends.server.util.Validator.*;
@@ -48,7 +54,8 @@
 * given structural objectclass, and also indicates which auxiliary
 * classes that may be included in the entry.
 */
public class DITContentRule
public final class DITContentRule
       implements SchemaFileElement
{
  /**
   * The fully-qualified name of this class for debugging purposes.
@@ -59,40 +66,38 @@
  // Indicates whether this content rule is declared "obsolete".
  private boolean isObsolete;
  private final boolean isObsolete;
  // The set of additional name-value pairs associated with this
  // content rule definition.
  private ConcurrentHashMap<String,CopyOnWriteArrayList<String>>
               extraProperties;
  private final Map<String,List<String>> extraProperties;
  // The set of names for this DIT content rule, in a mapping between
  // the all-lowercase form and the user-defined form.
  private ConcurrentHashMap<String,String> names;
  private final Map<String,String> names;
  // The structural objectclass for this DIT content rule.
  private final ObjectClass structuralClass;
  // The set of auxiliary objectclasses that entries with this content
  // rule may contain, in a mapping between the objectclass and the
  // user-defined name for that class.
  private CopyOnWriteArraySet<ObjectClass> auxiliaryClasses;
  private final Set<ObjectClass> auxiliaryClasses;
  // The set of optional attribute types for this DIT content rule.
  private CopyOnWriteArraySet<AttributeType> optionalAttributes;
  private final Set<AttributeType> optionalAttributes;
  // The set of prohibited attribute types for this DIT content rule.
  private CopyOnWriteArraySet<AttributeType> prohibitedAttributes;
  private final Set<AttributeType> prohibitedAttributes;
  // The set of required attribute types for this DIT content rule.
  private CopyOnWriteArraySet<AttributeType> requiredAttributes;
  private final Set<AttributeType> requiredAttributes;
  // The structural objectclass for this DIT content rule.
  private ObjectClass structuralClass;
  // The definition string used to create this DIT content rule.
  private final String definition;
  // The description for this attribute type.
  private String description;
  // The path to the schema file that contains this DIT content rule
  // definition.
  private String schemaFile;
  // The description for this DIT content rule.
  private final String description;
@@ -100,8 +105,12 @@
   * Creates a new DIT content rule definition with the provided
   * information.
   *
   * @param  definition            The definition string used to
   *                               create this DIT content rule.  It
   *                               must not be {@code null}.
   * @param  structuralClass       The structural objectclass for this
   *                               DIT content rule.
   *                               DIT content rule.  It must not be
   *                               {@code null}.
   * @param  names                 The set of names that may be used
   *                               to reference this DIT content rule.
   * @param  description           The description for this DIT
@@ -119,41 +128,139 @@
   * @param  extraProperties       A set of extra properties for this
   *                               DIT content rule.
   */
  public DITContentRule(ObjectClass structuralClass,
              ConcurrentHashMap<String,String> names,
              String description,
              CopyOnWriteArraySet<ObjectClass> auxiliaryClasses,
              CopyOnWriteArraySet<AttributeType> requiredAttributes,
              CopyOnWriteArraySet<AttributeType> optionalAttributes,
              CopyOnWriteArraySet<AttributeType> prohibitedAttributes,
              boolean isObsolete,
              ConcurrentHashMap<String,CopyOnWriteArrayList<String>>
                   extraProperties)
  public DITContentRule(String definition,
                        ObjectClass structuralClass,
                        Map<String,String> names, String description,
                        Set<ObjectClass> auxiliaryClasses,
                        Set<AttributeType> requiredAttributes,
                        Set<AttributeType> optionalAttributes,
                        Set<AttributeType> prohibitedAttributes,
                        boolean isObsolete,
                        Map<String,List<String>> extraProperties)
  {
    assert debugConstructor(CLASS_NAME,
                            new String[]
                            {
                              String.valueOf(structuralClass),
                              String.valueOf(names),
                              String.valueOf(description),
                              String.valueOf(auxiliaryClasses),
                              String.valueOf(requiredAttributes),
                              String.valueOf(optionalAttributes),
                              String.valueOf(prohibitedAttributes),
                              String.valueOf(isObsolete),
                              String.valueOf(extraProperties)
                            });
    assert debugConstructor(CLASS_NAME, String.valueOf(definition),
                            String.valueOf(structuralClass),
                            String.valueOf(names),
                            String.valueOf(description),
                            String.valueOf(auxiliaryClasses),
                            String.valueOf(requiredAttributes),
                            String.valueOf(optionalAttributes),
                            String.valueOf(prohibitedAttributes),
                            String.valueOf(isObsolete),
                            String.valueOf(extraProperties));
    this.structuralClass      = structuralClass;
    this.names                = names;
    this.description          = description;
    this.auxiliaryClasses     = auxiliaryClasses;
    this.requiredAttributes   = requiredAttributes;
    this.optionalAttributes   = optionalAttributes;
    this.prohibitedAttributes = prohibitedAttributes;
    this.isObsolete           = isObsolete;
    this.schemaFile           = null;
    this.extraProperties      = extraProperties;
    ensureNotNull(definition, structuralClass);
    this.definition      = definition;
    this.structuralClass = structuralClass;
    this.description     = description;
    this.isObsolete      = isObsolete;
    if ((names == null) || names.isEmpty())
    {
      this.names = new LinkedHashMap<String,String>(0);
    }
    else
    {
      this.names = new LinkedHashMap<String,String>(names);
    }
    if ((auxiliaryClasses == null) || auxiliaryClasses.isEmpty())
    {
      this.auxiliaryClasses = new LinkedHashSet<ObjectClass>(0);
    }
    else
    {
      this.auxiliaryClasses =
           new LinkedHashSet<ObjectClass>(auxiliaryClasses);
    }
    if ((requiredAttributes == null) || requiredAttributes.isEmpty())
    {
      this.requiredAttributes = new LinkedHashSet<AttributeType>(0);
    }
    else
    {
      this.requiredAttributes =
           new LinkedHashSet<AttributeType>(requiredAttributes);
    }
    if ((optionalAttributes == null) || optionalAttributes.isEmpty())
    {
      this.optionalAttributes = new LinkedHashSet<AttributeType>(0);
    }
    else
    {
      this.optionalAttributes =
           new LinkedHashSet<AttributeType>(optionalAttributes);
    }
    if ((prohibitedAttributes == null) ||
        prohibitedAttributes.isEmpty())
    {
      this.prohibitedAttributes = new LinkedHashSet<AttributeType>(0);
    }
    else
    {
      this.prohibitedAttributes =
           new LinkedHashSet<AttributeType>(prohibitedAttributes);
    }
    if ((extraProperties == null) || extraProperties.isEmpty())
    {
      this.extraProperties =
           new LinkedHashMap<String,List<String>>(0);
    }
    else
    {
      this.extraProperties =
           new LinkedHashMap<String,List<String>>(extraProperties);
    }
  }
  /**
   * Retrieves the definition string used to create this DIT content
   * rule.
   *
   * @return  The definition string used to create this DIT content
   *          rule.
   */
  public String getDefinition()
  {
    assert debugEnter(CLASS_NAME, "getDefinition");
    return definition;
  }
  /**
   * Creates a new instance of this DIT content rule based on the
   * definition string.  It will also preserve other state information
   * associated with this DIT content rule that is not included in the
   * definition string (e.g., the name of the schema file with which
   * it is associated).
   *
   * @return  The new instance of this DIT content rule based on the
   *          definition string.
   *
   * @throws  DirectoryException  If a problem occurs while attempting
   *                              to create a new DIT content rule
   *                              instance from the definition string.
   */
  public DITContentRule recreateFromDefinition()
         throws DirectoryException
  {
    ByteString value  = ByteStringFactory.create(definition);
    Schema     schema = DirectoryConfig.getSchema();
    DITContentRule dcr =
         DITContentRuleSyntax.decodeDITContentRule(value, schema);
    dcr.setSchemaFile(getSchemaFile());
    return dcr;
  }
@@ -173,22 +280,6 @@
  /**
   * Specifies the structural objectclass for this DIT content rule.
   *
   * @param  structuralClass  The structural objectclass for this DIT
   *                          content rule.
   */
  public void setStructuralClass(ObjectClass structuralClass)
  {
    assert debugEnter(CLASS_NAME, "setStructuralClass",
                      String.valueOf(structuralClass));
    this.structuralClass = structuralClass;
  }
  /**
   * Retrieves the set of names that may be used to reference this DIT
   * content rule.  The returned object will be a mapping between each
   * name in all lowercase characters and that name in a user-defined
@@ -197,7 +288,7 @@
   * @return  The set of names that may be used to reference this DIT
   *          content rule.
   */
  public ConcurrentHashMap<String,String> getNames()
  public Map<String,String> getNames()
  {
    assert debugEnter(CLASS_NAME, "getNames");
@@ -211,7 +302,7 @@
   * rule.
   *
   * @return  The primary name to use to reference this DIT content
   *          rule, or <CODE>null</CODE> if there is none.
   *          rule, or {@code null} if there is none.
   */
  public String getName()
  {
@@ -230,33 +321,15 @@
  /**
   * Specifies the set of names that may be used to reference this DIT
   * content rule.  The provided set must provide a mapping between
   * each name in all lowercase characters and that name in a
   * user-defined form (which may include mixed capitalization).
   *
   * @param  names  The set of names that may be used to reference
   *                this DIT content rule.
   */
  public void setNames(ConcurrentHashMap<String,String> names)
  {
    assert debugEnter(CLASS_NAME, "setNames", String.valueOf(names));
    this.names = names;
  }
  /**
   * Indicates whether the provided lowercase name may be used to
   * reference this DIT content rule.
   *
   * @param  lowerName  The name for which to make the determination,
   *                    in all lowercase characters.
   *
   * @return  <CODE>true</CODE> if the provided lowercase name may be
   *          used to reference this DIT content rule, or
   *          <CODE>false</CODE> if not.
   * @return  {@code true} if the provided lowercase name may be used
   *          to reference this DIT content rule, or {@code false} if
   *          not.
   */
  public boolean hasName(String lowerName)
  {
@@ -269,62 +342,34 @@
  /**
   * Adds the provided name to the set of names that may be used to
   * reference this DIT content rule.
   *
   * @param  name  The name to add to the set of names that may be
   *               used to reference this DIT content rule.
   */
  public void addName(String name)
  {
    assert debugEnter(CLASS_NAME, "addName", String.valueOf(name));
    String lowerName = toLowerCase(name);
    names.put(lowerName, name);
  }
  /**
   * Removes the provided lowercase name from the set of names that
   * may be used to reference this DIT content rule.
   *
   * @param  lowerName  The name to remove from the set of names that
   *                    may be used to reference this DIT content
   *                    rule, in all lowercase characters.
   */
  public void removeName(String lowerName)
  {
    assert debugEnter(CLASS_NAME, "removeName",
                      String.valueOf(lowerName));
    names.remove(lowerName);
  }
  /**
   * Retrieves the path to the schema file that contains the
   * Retrieves the name of the schema file that contains the
   * definition for this DIT content rule.
   *
   * @return  The path to the schema file that contains the definition
   *          for this DIT content rule, or <CODE>null</CODE> if it is
   *          not known or if it is not stored in any schema file.
   * @return  The name of the schema file that contains the definition
   *          for this DIT content rule, or {@code null} if it is not
   *          known or if it is not stored in any schema file.
   */
  public String getSchemaFile()
  {
    assert debugEnter(CLASS_NAME, "getSchemaFile");
    return schemaFile;
    List<String> values =
         extraProperties.get(SCHEMA_PROPERTY_FILENAME);
    if ((values == null) || values.isEmpty())
    {
      return null;
    }
    return values.get(0);
  }
  /**
   * Specifies the path to the schema file that contains the
   * Specifies the name of the schema file that contains the
   * definition for this DIT content rule.
   *
   * @param  schemaFile  The path to the schema file that contains the
   * @param  schemaFile  The name of the schema file that contains the
   *                     definition for this DIT content rule.
   */
  public void setSchemaFile(String schemaFile)
@@ -332,7 +377,7 @@
    assert debugEnter(CLASS_NAME, "setSchemaFile",
                      String.valueOf(schemaFile));
    this.schemaFile = schemaFile;
    setExtraProperty(SCHEMA_PROPERTY_FILENAME, schemaFile);
  }
@@ -341,7 +386,7 @@
   * Retrieves the description for this DIT content rule.
   *
   * @return  The description for this DIT content rule, or
   *          <CODE>null</CODE> if there is none.
   *          {@code null} if there is none.
   */
  public String getDescription()
  {
@@ -353,28 +398,13 @@
  /**
   * Specifies the description for this DIT content rule.
   *
   * @param  description  The description for this DIT content rule.
   */
  public void setDescription(String description)
  {
    assert debugEnter(CLASS_NAME, "setDescription",
                      String.valueOf(description));
    this.description = description;
  }
  /**
   * Retrieves the set of auxiliary objectclasses that may be used for
   * entries associated with this DIT content rule.
   *
   * @return  The set of auxiliary objectclasses that may be used for
   *          entries associated with this DIT content rule.
   */
  public CopyOnWriteArraySet<ObjectClass> getAuxiliaryClasses()
  public Set<ObjectClass> getAuxiliaryClasses()
  {
    assert debugEnter(CLASS_NAME, "getAuxiliaryClasses");
@@ -384,68 +414,15 @@
  /**
   * Specifies the set of auxiliary objectclasses that may be used for
   * entries associated with this DIT content rule.
   *
   * @param  auxiliaryClasses  The set of auxiliary objectclasses that
   *                           may be used for entries associated with
   *                           this DIT content rule.
   */
  public void setAuxiliaryClasses(
                   CopyOnWriteArraySet<ObjectClass> auxiliaryClasses)
  {
    assert debugEnter(CLASS_NAME, "setAuxiliaryClasses",
                      String.valueOf(auxiliaryClasses));
    this.auxiliaryClasses = auxiliaryClasses;
  }
  /**
   * Adds the specified auxiliary objectclass to this DIT content
   * rule.
   *
   * @param  auxiliaryClass  The auxiliary class to add to this DIT
   *                         content rule.
   */
  public void addAuxiliaryClass(ObjectClass auxiliaryClass)
  {
    assert debugEnter(CLASS_NAME, "addAuxiliaryClass",
                      String.valueOf(auxiliaryClass));
    auxiliaryClasses.add(auxiliaryClass);
  }
  /**
   * Removes the specified auxiliary objectclass from this DIT content
   * rule.
   *
   * @param  auxiliaryClass  The auxiliary class to remove from this
   *                         DIT content rule.
   */
  public void removeAuxiliaryClass(ObjectClass auxiliaryClass)
  {
    assert debugEnter(CLASS_NAME, "removeAuxiliaryClass",
                      String.valueOf(auxiliaryClass));
    auxiliaryClasses.remove(auxiliaryClass);
  }
  /**
   * Indicates whether the provided auxiliary objectclass is allowed
   * for use by this DIT content rule.
   *
   * @param  auxiliaryClass  The auxiliary objectclass for which to
   *                         make the determination.
   *
   * @return  <CODE>true</CODE> if the provided auxiliary objectclass
   *          is allowed for use by this DIT content rule, or
   *          <CODE>false</CODE> if not.
   * @return  {@code true} if the provided auxiliary objectclass is
   *          allowed for use by this DIT content rule, or
   *          {@code false} if not.
   */
  public boolean isAllowedAuxiliaryClass(ObjectClass auxiliaryClass)
  {
@@ -463,7 +440,7 @@
   * @return  The set of required attributes for this DIT content
   *          rule.
   */
  public CopyOnWriteArraySet<AttributeType> getRequiredAttributes()
  public Set<AttributeType> getRequiredAttributes()
  {
    assert debugEnter(CLASS_NAME, "getRequiredAttributes");
@@ -479,9 +456,8 @@
   * @param  attributeType  The attribute type for which to make the
   *                        determination.
   *
   * @return  <CODE>true</CODE> if the provided attribute type is
   *          required by this DIT content rule, or <CODE>false</CODE>
   *          if not.
   * @return  {@code true} if the provided attribute type is required
   *          by this DIT content rule, or {@code false} if not.
   */
  public boolean isRequired(AttributeType attributeType)
  {
@@ -494,67 +470,13 @@
  /**
   * Specifies the set of required attributes for this DIT content
   * rule.
   *
   * @param  requiredAttributes  The set of required attributes for
   *                             this DIT content rule.
   */
  public void setRequiredAttributes(CopyOnWriteArraySet<AttributeType>
                                         requiredAttributes)
  {
    assert debugEnter(CLASS_NAME, "setRequiredAttributes",
                      String.valueOf(requiredAttributes));
    this.requiredAttributes = requiredAttributes;
  }
  /**
   * Adds the provided attribute to the set of required attributes for
   * this DIT content rule.
   *
   * @param  attributeType  The attribute type to add to the set of
   *                        required attributes for this DIT content
   *                        rule.
   */
  public void addRequiredAttribute(AttributeType attributeType)
  {
    assert debugEnter(CLASS_NAME, "addRequiredAttribute",
                      String.valueOf(attributeType));
    requiredAttributes.add(attributeType);
  }
  /**
   * Removes the provided attribute from the set of required
   * attributes for this DIT content rule.
   *
   * @param  attributeType  The attribute type to remove from the set
   *                        of required attributes for this DIT
   *                        content rule.
   */
  public void removeRequiredAttribute(AttributeType attributeType)
  {
    assert debugEnter(CLASS_NAME, "removeRequiredAttribute",
                      String.valueOf(attributeType));
    requiredAttributes.remove(attributeType);
  }
  /**
   * Retrieves the set of optional attributes for this DIT content
   * rule.
   *
   * @return  The set of optional attributes for this DIT content
   *          rule.
   */
  public CopyOnWriteArraySet<AttributeType> getOptionalAttributes()
  public Set<AttributeType> getOptionalAttributes()
  {
    assert debugEnter(CLASS_NAME, "getOptionalAttributes");
@@ -570,9 +492,8 @@
   * @param  attributeType  The attribute type for which to make the
   *                        determination.
   *
   * @return  <CODE>true</CODE> if the provided attribute type is
   *          optional for this DIT content rule, or
   *          <CODE>false</CODE> if not.
   * @return  {@code true} if the provided attribute type is optional
   *          for this DIT content rule, or {@code false} if not.
   */
  public boolean isOptional(AttributeType attributeType)
  {
@@ -585,69 +506,15 @@
  /**
   * Specifies the set of optional attributes for this DIT content
   * rule.
   *
   * @param  optionalAttributes  The set of optional attributes for
   *                             this DIT content rule.
   */
  public void setOptionalAttributes(CopyOnWriteArraySet<AttributeType>
                                         optionalAttributes)
  {
    assert debugEnter(CLASS_NAME, "setOptionalAttributes",
                      String.valueOf(optionalAttributes));
    this.optionalAttributes = optionalAttributes;
  }
  /**
   * Adds the provided attribute to the set of optional attributes for
   * this DIT content rule.
   *
   * @param  attributeType  The attribute type to add to the set of
   *                        optional attributes for this DIT content
   *                        rule.
   */
  public void addOptionalAttribute(AttributeType attributeType)
  {
    assert debugEnter(CLASS_NAME, "addOptionalAttribute",
                      String.valueOf(attributeType));
    optionalAttributes.add(attributeType);
  }
  /**
   * Removes the provided attribute from the set of optional
   * attributes for this DIT content rule.
   *
   * @param  attributeType  The attribute type to remove from the set
   *                        of optional attributes for this DIT
   *                        content rule.
   */
  public void removeOptionalAttribute(AttributeType attributeType)
  {
    assert debugEnter(CLASS_NAME, "removeOptionalAttribute",
                      String.valueOf(attributeType));
    optionalAttributes.remove(attributeType);
  }
  /**
   * Indicates whether the provided attribute type is in the list of
   * required or optional attributes for this DIT content rule.
   *
   * @param  attributeType  The attribute type for which to make the
   *                        determination.
   *
   * @return  <CODE>true</CODE> if the provided attribute type is
   *          required or allowed for this DIT content rule, or
   *          <CODE>false</CODE> if it is not.
   * @return  {@code true} if the provided attribute type is required
   *          or allowed for this DIT content rule, or {@code false}
   *          if it is not.
   */
  public boolean isRequiredOrOptional(AttributeType attributeType)
  {
@@ -672,9 +539,9 @@
   *                        allowed for an objectclass will be
   *                        acceptable.
   *
   * @return  <CODE>true</CODE> if the provided attribute type is
   *          required or allowed for this DIT content rule, or
   *          <CODE>false</CODE> if it is not.
   * @return  {@code true} if the provided attribute type is required
   *          or allowed for this DIT content rule, or {@code false}
   *          if it is not.
   */
  public boolean isRequiredOrOptional(AttributeType attributeType,
                                      boolean acceptEmpty)
@@ -702,7 +569,7 @@
   * @return  The set of prohibited attributes for this DIT content
   *          rule.
   */
  public CopyOnWriteArraySet<AttributeType> getProhibitedAttributes()
  public Set<AttributeType> getProhibitedAttributes()
  {
    assert debugEnter(CLASS_NAME, "getProhibitedAttributes");
@@ -718,9 +585,9 @@
   * @param  attributeType  The attribute type for which to make the
   *                        determination.
   *
   * @return  <CODE>true</CODE> if the provided attribute type is
   *          prohibited for this DIT content rule, or
   *          <CODE>false</CODE> if not.
   * @return  {@code true} if the provided attribute type is
   *          prohibited for this DIT content rule, or {@code false}
   *          if not.
   */
  public boolean isProhibited(AttributeType attributeType)
  {
@@ -733,65 +600,10 @@
  /**
   * Specifies the set of prohibited attributes for this DIT content
   * rule.
   *
   * @param  prohibitedAttributes  The set of prohibited attributes
   *                               for this DIT content rule.
   */
  public void setProhibitedAttributes(
                   CopyOnWriteArraySet<AttributeType>
                       prohibitedAttributes)
  {
    assert debugEnter(CLASS_NAME, "setProhibitedAttributes",
                      String.valueOf(prohibitedAttributes));
    this.prohibitedAttributes = prohibitedAttributes;
  }
  /**
   * Adds the provided attribute to the set of prohibited attributes
   * for this DIT content rule.
   *
   * @param  attributeType  The attribute type to add to the set of
   *                        prohibited attributes for this DIT
   *                        content rule.
   */
  public void addProhibitedAttribute(AttributeType attributeType)
  {
    assert debugEnter(CLASS_NAME, "addProhibitedAttribute",
                      String.valueOf(attributeType));
    prohibitedAttributes.add(attributeType);
  }
  /**
   * Removes the provided attribute from the set of prohibited
   * attributes for this DIT content rule.
   *
   * @param  attributeType  The attribute type to remove from the set
   *                        of prohibited attributes for this DIT
   *                        content rule.
   */
  public void removeProhibitedAttribute(AttributeType attributeType)
  {
    assert debugEnter(CLASS_NAME, "removeProhibitedAttribute",
                      String.valueOf(attributeType));
    prohibitedAttributes.remove(attributeType);
  }
  /**
   * Indicates whether this DIT content rule is declared "obsolete".
   *
   * @return  <CODE>true</CODE> if this DIT content rule is declared
   *          "obsolete", or <CODE>false</CODE> if it is not.
   * @return  {@code true} if this DIT content rule is declared
   *          "obsolete", or {@code false} if it is not.
   */
  public boolean isObsolete()
  {
@@ -803,33 +615,15 @@
  /**
   * Specifies whether this DIT content rule is declared "obsolete".
   *
   * @param  isObsolete  Specifies whether this DIT content rule is
   *                     declared "obsolete".
   */
  public void setObsolete(boolean isObsolete)
  {
    assert debugEnter(CLASS_NAME, "setObsolete",
                      String.valueOf(isObsolete));
    this.isObsolete = isObsolete;
  }
  /**
   * Retrieves a mapping between the names of any extra non-standard
   * properties that may be associated with this DIT content rule and
   * the value for that property.  The caller may alter the contents
   * of this mapping.
   * the value for that property.
   *
   * @return  A mapping between the names of any extra non-standard
   *          properties that may be associated with this DIT content
   *          rule and the value for that property.
   */
  public ConcurrentHashMap<String,CopyOnWriteArrayList<String>>
              getExtraProperties()
  public Map<String,List<String>> getExtraProperties()
  {
    assert debugEnter(CLASS_NAME, "getExtraProperties");
@@ -846,11 +640,10 @@
   *                       to retrieve the value.
   *
   * @return  The value of the specified "extra" property for this DIT
   *          content rule, or <CODE>null</CODE> if no such property
   *          is defined.
   *          content rule, or {@code null} if no such property is
   *          defined.
   */
  public CopyOnWriteArrayList<String>
              getExtraProperty(String propertyName)
  public List<String> getExtraProperty(String propertyName)
  {
    assert debugEnter(CLASS_NAME, "getExtraProperty",
                      String.valueOf(propertyName));
@@ -861,6 +654,66 @@
  /**
   * Specifies the provided "extra" property for this DIT content
   * rule.
   *
   * @param  name   The name for the "extra" property.  It must not be
   *                {@code null}.
   * @param  value  The value for the "extra" property, or
   *                {@code null} if the property is to be removed.
   */
  public void setExtraProperty(String name, String value)
  {
    assert debugEnter(CLASS_NAME, "setExtraProperty",
                      String.valueOf(name), String.valueOf(value));
    ensureNotNull(name);
    if (value == null)
    {
      extraProperties.remove(name);
    }
    else
    {
      LinkedList<String> values = new LinkedList<String>();
      values.add(value);
      extraProperties.put(name, values);
    }
  }
  /**
   * Specifies the provided "extra" property for this DIT content
   * rule.
   *
   * @param  name    The name for the "extra" property.  It must not
   *                 be {@code null}.
   * @param  values  The set of value for the "extra" property, or
   *                 {@code null} if the property is to be removed.
   */
  public void setExtraProperty(String name, List<String> values)
  {
    assert debugEnter(CLASS_NAME, "setExtraProperty",
                      String.valueOf(name), String.valueOf(values));
    ensureNotNull(name);
    if ((values == null) || values.isEmpty())
    {
      extraProperties.remove(name);
    }
    else
    {
      LinkedList<String> valuesCopy = new LinkedList<String>(values);
      extraProperties.put(name, valuesCopy);
    }
  }
  /**
   * Indicates whether the provided object is equal to this DIT
   * content rule.  The object will be considered equal if it is a DIT
   * content rule for the same structural objectclass and the same
@@ -871,8 +724,8 @@
   *
   * @param  o  The object for which to make the determination.
   *
   * @return  <CODE>true</CODE> if the provided object is equal to
   *          this DIT content rule, or <CODE>false</CODE> if not.
   * @return  {@code true} if the provided object is equal to
   *          this DIT content rule, or {@code false} if not.
   */
  public boolean equals(Object o)
  {
@@ -1112,8 +965,13 @@
    {
      for (String property : extraProperties.keySet())
      {
        CopyOnWriteArrayList<String> valueList =
             extraProperties.get(property);
        if ((! includeFileElement) &&
            property.equals(SCHEMA_PROPERTY_FILENAME))
        {
          continue;
        }
        List<String> valueList = extraProperties.get(property);
        buffer.append(" ");
        buffer.append(property);
@@ -1140,16 +998,6 @@
      }
    }
    if (includeFileElement && (schemaFile != null) &&
        (! extraProperties.containsKey(SCHEMA_PROPERTY_FILENAME)))
    {
      buffer.append(" ");
      buffer.append(SCHEMA_PROPERTY_FILENAME);
      buffer.append(" '");
      buffer.append(schemaFile);
      buffer.append("'");
    }
    buffer.append(" )");
  }
}
opendj-sdk/opends/src/server/org/opends/server/types/DITStructureRule.java
@@ -22,16 +22,21 @@
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2006 Sun Microsystems, Inc.
 *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
 */
package org.opends.server.types;
import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.opends.server.schema.DITStructureRuleSyntax;
import static org.opends.server.loggers.Debug.*;
import static org.opends.server.loggers.Error.*;
@@ -39,6 +44,7 @@
import static org.opends.server.messages.MessageHandler.*;
import static org.opends.server.util.ServerConstants.*;
import static org.opends.server.util.StaticUtils.*;
import static org.opends.server.util.Validator.*;
@@ -46,7 +52,8 @@
 * This class defines a DIT structure rule, which is used to indicate
 * the types of children that entries may have.
 */
public class DITStructureRule
public final class DITStructureRule
       implements SchemaFileElement
{
  /**
   * The fully-qualified name of this class for debugging purposes.
@@ -57,38 +64,39 @@
  // Indicates whether this DIT structure rule is declared "obsolete".
  private boolean isObsolete;
  private final boolean isObsolete;
  // The rule ID for this DIT structure rule.
  private final int ruleID;
  // The name form for this DIT structure rule.
  private final NameForm nameForm;
  // The set of additional name-value pairs associated with this DIT
  // structure rule.
  private ConcurrentHashMap<String,CopyOnWriteArrayList<String>>
               extraProperties;
  private final Map<String,List<String>> extraProperties;
  // The set of names for this DIT structure rule, in a mapping
  // between the all-lowercase form and the user-defined form.
  private ConcurrentHashMap<String,String> names;
  private final Map<String,String> names;
  // The set of superior DIT structure rules.
  private CopyOnWriteArraySet<DITStructureRule> superiorRules;
  private final Set<DITStructureRule> superiorRules;
  // The rule ID for this DIT structure rule.
  private int ruleID;
  // The name form for this DIT structure rule.
  private NameForm nameForm;
  // The definition string for this DIT structure rule.
  private final String definition;
  // The description for this DIT structure rule.
  private String description;
  // The path to the schema file that contains this DIT structure rule
  // definition.
  private String schemaFile;
  private final String description;
  /**
   * Creates a new DIT structure rule with the provided information.
   *
   * @param  definition       The definition string used to create
   *                          this DIT structure rule.  It must not be
   *                          {@code null}.
   * @param  names            The set of names for this DIT structure
   *                          rule, mapping the lowercase names to the
   *                          user-defined values.
@@ -104,33 +112,104 @@
   * @param  extraProperties  The set of "extra" properties associated
   *                          with this DIT structure rules.
   */
  public DITStructureRule(ConcurrentHashMap<String,String> names,
              int ruleID, String description,  boolean isObsolete,
              NameForm nameForm,
              CopyOnWriteArraySet<DITStructureRule> superiorRules,
              ConcurrentHashMap<String,CopyOnWriteArrayList<String>>
                   extraProperties)
  public DITStructureRule(String definition, Map<String,String> names,
                          int ruleID, String description,
                          boolean isObsolete, NameForm nameForm,
                          Set<DITStructureRule> superiorRules,
                          Map<String,List<String>> extraProperties)
  {
    assert debugConstructor(CLASS_NAME,
                            new String[]
                            {
                              String.valueOf(names),
                              String.valueOf(ruleID),
                              String.valueOf(description),
                              String.valueOf(isObsolete),
                              String.valueOf(nameForm),
                              String.valueOf(superiorRules),
                              String.valueOf(extraProperties)
                            });
    assert debugConstructor(CLASS_NAME, String.valueOf(definition),
                            String.valueOf(names),
                            String.valueOf(ruleID),
                            String.valueOf(description),
                            String.valueOf(isObsolete),
                            String.valueOf(nameForm),
                            String.valueOf(superiorRules),
                            String.valueOf(extraProperties));
    this.names           = names;
    this.ruleID          = ruleID;
    this.description     = description;
    this.isObsolete      = isObsolete;
    this.nameForm        = nameForm;
    this.superiorRules   = superiorRules;
    this.schemaFile      = null;
    this.extraProperties = extraProperties;
    ensureNotNull(definition);
    this.definition  = definition;
    this.ruleID      = ruleID;
    this.description = description;
    this.isObsolete  = isObsolete;
    this.nameForm    = nameForm;
    if ((names == null) || names.isEmpty())
    {
      this.names = new LinkedHashMap<String,String>(0);
    }
    else
    {
      this.names = new LinkedHashMap<String,String>(names);
    }
    if ((superiorRules == null) || superiorRules.isEmpty())
    {
      this.superiorRules = new LinkedHashSet<DITStructureRule>(0);
    }
    else
    {
      this.superiorRules =
           new LinkedHashSet<DITStructureRule>(superiorRules);
    }
    if ((extraProperties == null) || extraProperties.isEmpty())
    {
      this.extraProperties =
           new LinkedHashMap<String,List<String>>(0);
    }
    else
    {
      this.extraProperties =
           new LinkedHashMap<String,List<String>>(extraProperties);
    }
  }
  /**
   * Retrieves the definition string used to create this DIT structure
   * rule.
   *
   * @return  The definition string used to create this DIT structure
   *          rule.
   */
  public String getDefinition()
  {
    assert debugEnter(CLASS_NAME, "getDefinition");
    return definition;
  }
  /**
   * Creates a new instance of this DIT structure rule based on the
   * definition string.  It will also preserve other state information
   * associated with this DIT structure rule that is not included in
   * the definition string (e.g., the name of the schema file with
   * which it is associated).
   *
   * @return  The new instance of this DIT structure rule based on the
   *          definition string.
   *
   * @throws  DirectoryException  If a problem occurs while attempting
   *                              to create a new DIT structure rule
   *                              instance from the definition string.
   */
  public DITStructureRule recreateFromDefinition()
         throws DirectoryException
  {
    ByteString value  = ByteStringFactory.create(definition);
    Schema     schema = DirectoryConfig.getSchema();
    DITStructureRule dsr =
         DITStructureRuleSyntax.decodeDITStructureRule(value, schema,
                                                       false);
    dsr.setSchemaFile(getSchemaFile());
    return dsr;
  }
@@ -144,7 +223,7 @@
   * @return  The set of names that may be used to reference this DIT
   *          structure rule.
   */
  public ConcurrentHashMap<String,String> getNames()
  public Map<String,String> getNames()
  {
    assert debugEnter(CLASS_NAME, "getNames");
@@ -154,31 +233,13 @@
  /**
   * Specifies the set of names that may be used to reference this DIT
   * structure rule.  The provided set must contain a mapping between
   * each name in all lowercase characters and the name in a
   * user-defined form (which may include mixed capitalization).
   *
   * @param  names  The set of names that may be used to reference
   *                this attribute type.
   */
  public void setNames(ConcurrentHashMap<String,String> names)
  {
    assert debugEnter(CLASS_NAME, "setNames", String.valueOf(names));
    this.names = names;
  }
  /**
   * Indicates whether this DIT structure rule has the specified name.
   *
   * @param  lowerName  The lowercase name for which to make the
   *                    determination.
   *
   * @return  <CODE>true</CODE> if the specified name is assigned to
   *          this DIT structure rule, or <CODE>false</CODE> if not.
   * @return  {@code true} if the specified name is assigned to this
   *          DIT structure rule, or {@code false} if not.
   */
  public boolean hasName(String lowerName)
  {
@@ -191,41 +252,6 @@
  /**
   * Adds the specified name to the set of names for this DIT
   * structure rule.
   *
   * @param  name  The name to add to the set of names for this DIT
   *               structure rule.
   */
  public void addName(String name)
  {
    assert debugEnter(CLASS_NAME, "addName", String.valueOf(name));
    String lowerName = toLowerCase(name);
    names.put(lowerName, name);
  }
  /**
   * Removes the specified name from the set of names for this DIT
   * structure rule.  This will have no effect if the specified name
   * is not associated with this attribute type.
   *
   * @param  lowerName  The lowercase name to remove from the set of
   *                    names for this DIT structure rule.
   */
  public void removeName(String lowerName)
  {
    assert debugEnter(CLASS_NAME, "removeName",
                      String.valueOf(lowerName));
    names.remove(lowerName);
  }
  /**
   * Retrieves the rule ID for this DIT structure rule.
   *
   * @return  The rule ID for this DIT structure rule.
@@ -240,21 +266,6 @@
  /**
   * Specifies the rule ID for this DIT structure rule.
   *
   * @param  ruleID  The rule ID for this DIT structure rule.
   */
  public void setRuleID(int ruleID)
  {
    assert debugEnter(CLASS_NAME, "setRuleID",
                      String.valueOf(ruleID));
    this.ruleID = ruleID;
  }
  /**
   * Retrieves the name or rule ID for this DIT structure rule.  If it
   * has one or more names, then the primary name will be returned.
   * If it does not have any names, then the rule ID will be returned.
@@ -278,44 +289,25 @@
  /**
   * Indicates whether this DIT structure rule has the specified name
   * or rule ID.
   *
   * @param  lowerValue  The lowercase value for which to make the
   *                     determination.
   *
   * @return  <CODE>true</CODE> if the provided value matches the rule
   *          ID or one of the names assigned to this DIT structure
   *          rule, or <CODE>false</CODE> if not.
   */
  public boolean hasNameOrOID(String lowerValue)
  {
    assert debugEnter(CLASS_NAME, "hasNameOrOID",
                      String.valueOf(lowerValue));
    if (names.containsKey(lowerValue))
    {
      return true;
    }
    return lowerValue.equals(String.valueOf(ruleID));
  }
  /**
   * Retrieves the path to the schema file that contains the
   * definition for this DIT structure rule.
   *
   * @return  The path to the schema file that contains the definition
   *          for this DIT structure rule, or <CODE>null</CODE> if it
   *          for this DIT structure rule, or {@code null} if it
   *          is not known or if it is not stored in any schema file.
   */
  public String getSchemaFile()
  {
    assert debugEnter(CLASS_NAME, "getSchemaFile");
    return schemaFile;
    List<String> values =
         extraProperties.get(SCHEMA_PROPERTY_FILENAME);
    if ((values == null) || values.isEmpty())
    {
      return null;
    }
    return values.get(0);
  }
@@ -332,7 +324,7 @@
    assert debugEnter(CLASS_NAME, "setSchemaFile",
                      String.valueOf(schemaFile));
    this.schemaFile = schemaFile;
    setExtraProperty(SCHEMA_PROPERTY_FILENAME, schemaFile);
  }
@@ -352,20 +344,6 @@
  /**
   * Specifies the description for this DIT structure rule.
   *
   * @param  description  The description for this DIT structure rule.
   */
  public void setDescription(String description)
  {
    assert debugEnter(CLASS_NAME, "setDescription", description);
    this.description = description;
  }
  /**
   * Retrieves the name form for this DIT structure rule.
   *
   * @return  The name form for this DIT structure rule.
@@ -380,21 +358,6 @@
  /**
   * Specifies the name form for this DIT structure rule.
   *
   * @param  nameForm  The name form for this DIT structure rule.
   */
  public void setNameForm(NameForm nameForm)
  {
    assert debugEnter(CLASS_NAME, "setNameForm",
                      String.valueOf(nameForm));
    this.nameForm = nameForm;
  }
  /**
   * Retrieves the structural objectclass for the name form with which
   * this DIT structure rule is associated.
   *
@@ -415,7 +378,7 @@
   *
   * @return  The set of superior rules for this DIT structure rule.
   */
  public CopyOnWriteArraySet<DITStructureRule> getSuperiorRules()
  public Set<DITStructureRule> getSuperiorRules()
  {
    assert debugEnter(CLASS_NAME, "getSuperiorRules");
@@ -428,8 +391,8 @@
   * Indicates whether this DIT structure rule has one or more
   * superior rules.
   *
   * @return  <CODE>true</CODE> if this DIT structure rule has one or
   *          more superior rules, or <CODE>false</CODE> if not.
   * @return  {@code true} if this DIT structure rule has one or more
   *          superior rules, or {@code false} if not.
   */
  public boolean hasSuperiorRules()
  {
@@ -441,62 +404,10 @@
  /**
   * Specifies the set of superior rules for this DIT structure rule.
   *
   * @param  superiorRules  The set of superior rules for this DIT
   *                        structure rule.
   */
  public void setSuperiorRules(CopyOnWriteArraySet<DITStructureRule>
                                    superiorRules)
  {
    assert debugEnter(CLASS_NAME, "setSuperiorRules",
                      String.valueOf(superiorRules));
    this.superiorRules = superiorRules;
  }
  /**
   * Adds the provided rule as a superior rule for this DIT structure
   * rule.
   *
   * @param  superiorRule  The superior rule to add to this DIT
   *                       structure rule.
   */
  public void addSuperiorRule(DITStructureRule superiorRule)
  {
    assert debugEnter(CLASS_NAME, "addSuperiorRule",
                      String.valueOf(superiorRule));
    superiorRules.add(superiorRule);
  }
  /**
   * Removes the provided rule as a superior rule for this DIT
   * structure rule.  It will have no effect if the provided rule is
   * not a superior rule for this DIT structure rule.
   *
   * @param  superiorRule  The superior rule to remove from this DIT
   *                       structure rule.
   */
  public void removeSuperiorRule(DITStructureRule superiorRule)
  {
    assert debugEnter(CLASS_NAME, "removeSuperiorRule",
                      String.valueOf(superiorRule));
    superiorRules.remove(superiorRule);
  }
  /**
   * Indicates whether this DIT structure rule is declared "obsolete".
   *
   * @return  <CODE>true</CODE> if this DIT structure rule is declared
   *          "obsolete", or <CODE>false</CODE> if not.
   * @return  {@code true} if this DIT structure rule is declared
   *          "obsolete", or {@code false} if not.
   */
  public boolean isObsolete()
  {
@@ -508,33 +419,15 @@
  /**
   * Specifies whether this DIT structure rule is declared "obsolete".
   *
   * @param  isObsolete  Specifies whether this DIT structure rule is
   *                     declared "obsolete".
   */
  public void setObsolete(boolean isObsolete)
  {
    assert debugEnter(CLASS_NAME, "setObsolete",
                      String.valueOf(isObsolete));
    this.isObsolete = isObsolete;
  }
  /**
   * Retrieves a mapping between the names of any extra non-standard
   * properties that may be associated with this DIT structure rule
   * and the value for that property.  The caller may alter the
   * contents of this mapping.
   * and the value for that property.
   *
   * @return  A mapping between the names of any extra non-standard
   *          properties that may be associated with this DIT
   *          structure rule and the value for that property.
   */
  public ConcurrentHashMap<String,CopyOnWriteArrayList<String>>
              getExtraProperties()
  public Map<String,List<String>> getExtraProperties()
  {
    assert debugEnter(CLASS_NAME, "getExtraProperties");
@@ -551,11 +444,10 @@
   *                       to retrieve the value.
   *
   * @return  The value of the specified "extra" property for this DIT
   *          structure rule, or <CODE>null</CODE> if no such property
   *          is defined.
   *          structure rule, or {@code null} if no such property is
   *          defined.
   */
  public CopyOnWriteArrayList<String>
              getExtraProperty(String propertyName)
  public List<String> getExtraProperty(String propertyName)
  {
    assert debugEnter(CLASS_NAME, "getExtraProperty",
                      String.valueOf(propertyName));
@@ -566,14 +458,74 @@
  /**
   * Specifies the provided "extra" property for this DIT structure
   * rule.
   *
   * @param  name   The name for the "extra" property.  It must not be
   *                {@code null}.
   * @param  value  The value for the "extra" property, or
   *                {@code null} if the property is to be removed.
   */
  public void setExtraProperty(String name, String value)
  {
    assert debugEnter(CLASS_NAME, "setExtraProperty",
                      String.valueOf(name), String.valueOf(value));
    ensureNotNull(name);
    if (value == null)
    {
      extraProperties.remove(name);
    }
    else
    {
      LinkedList<String> values = new LinkedList<String>();
      values.add(value);
      extraProperties.put(name, values);
    }
  }
  /**
   * Specifies the provided "extra" property for this DIT structure
   * rule.
   *
   * @param  name    The name for the "extra" property.  It must not
   *                 be {@code null}.
   * @param  values  The set of value for the "extra" property, or
   *                 {@code null} if the property is to be removed.
   */
  public void setExtraProperty(String name, List<String> values)
  {
    assert debugEnter(CLASS_NAME, "setExtraProperty",
                      String.valueOf(name), String.valueOf(values));
    ensureNotNull(name);
    if ((values == null) || values.isEmpty())
    {
      extraProperties.remove(name);
    }
    else
    {
      LinkedList<String> valuesCopy = new LinkedList<String>(values);
      extraProperties.put(name, valuesCopy);
    }
  }
  /**
   * Indicates whether the provided object is equal to this DIT
   * structure rule.  The object will be considered equal if it is a
   * DIT structure rule with the same OID as the current type.
   *
   * @param  o  The object for which to make the determination.
   *
   * @return  <CODE>true</CODE> if the provided object is equal to
   *          this attribute, or <CODE>false</CODE> if not.
   * @return  {@code true} if the provided object is equal to this
   *          attribute, or {@code false} if not.
   */
  public boolean equals(Object o)
  {
@@ -718,8 +670,13 @@
    {
      for (String property : extraProperties.keySet())
      {
        CopyOnWriteArrayList<String> valueList =
             extraProperties.get(property);
        if ((! includeFileElement) &&
            property.equals(SCHEMA_PROPERTY_FILENAME))
        {
          continue;
        }
        List<String> valueList = extraProperties.get(property);
        buffer.append(" ");
        buffer.append(property);
@@ -746,16 +703,6 @@
      }
    }
    if (includeFileElement && (schemaFile != null) &&
        (! extraProperties.containsKey(SCHEMA_PROPERTY_FILENAME)))
    {
      buffer.append(" ");
      buffer.append(SCHEMA_PROPERTY_FILENAME);
      buffer.append(" '");
      buffer.append(schemaFile);
      buffer.append("'");
    }
    buffer.append(" )");
  }
}
opendj-sdk/opends/src/server/org/opends/server/types/MatchingRuleUse.java
@@ -22,22 +22,27 @@
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2006 Sun Microsystems, Inc.
 *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
 */
package org.opends.server.types;
import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.opends.server.api.MatchingRule;
import org.opends.server.schema.MatchingRuleUseSyntax;
import static org.opends.server.loggers.Debug.*;
import static org.opends.server.util.ServerConstants.*;
import static org.opends.server.util.StaticUtils.*;
import static org.opends.server.util.Validator.*;
@@ -47,7 +52,8 @@
 * the set of attribute types that may be used for a given matching
 * rule.
 */
public class MatchingRuleUse
public final class MatchingRuleUse
       implements SchemaFileElement
{
  /**
   * The fully-qualified name of this class for debugging purposes.
@@ -58,32 +64,30 @@
  // Indicates whether this matching rule use is declared "obsolete".
  private boolean isObsolete;
  private final boolean isObsolete;
  // The set of additional name-value pairs associated with this
  // matching rule use definition.
  private final Map<String,List<String>> extraProperties;
  // The set of names that may be used to refer to this matching rule
  // use, mapped between their all-lowercase representations and the
  // user-defined representations.
  private ConcurrentHashMap<String,String> names;
  // The set of attribute types with which this matching rule use is
  // associated.
  private CopyOnWriteArraySet<AttributeType> attributes;
  // The set of additional name-value pairs associated with this
  // matching rule use definition.
  private ConcurrentHashMap<String,CopyOnWriteArrayList<String>>
               extraProperties;
  private final Map<String,String> names;
  // The matching rule with which this matching rule use is
  // associated.
  private MatchingRule matchingRule;
  private final MatchingRule matchingRule;
  // The set of attribute types with which this matching rule use is
  // associated.
  private final Set<AttributeType> attributes;
  // The definition string used to create this matching rule use.
  private final String definition;
  // The description for this matching rule use.
  private String description;
  // The path to the schema file that contains this matching rule use
  // definition.
  private String schemaFile;
  private final String description;
@@ -91,8 +95,11 @@
   * Creates a new matching rule use definition with the provided
   * information.
   *
   * @param  definition       The definition string used to create
   *                          this matching rule use.  It must not be
   *                          {@code null}.
   * @param  matchingRule     The matching rule for this matching rule
   *                          use.
   *                          use.  It must not be {@code null}.
   * @param  names            The set of names for this matching rule
   *                          use.
   * @param  description      The description for this matching rule
@@ -104,32 +111,100 @@
   * @param  extraProperties  A set of "extra" properties that may be
   *                          associated with this matching rule use.
   */
  public MatchingRuleUse(MatchingRule matchingRule,
              ConcurrentHashMap<String,String> names,
              String description, boolean isObsolete,
              CopyOnWriteArraySet<AttributeType> attributes,
              ConcurrentHashMap<String,CopyOnWriteArrayList<String>>
                   extraProperties)
  public MatchingRuleUse(String definition, MatchingRule matchingRule,
                         Map<String,String> names, String description,
                         boolean isObsolete,
                         Set<AttributeType> attributes,
                         Map<String,List<String>> extraProperties)
  {
    assert debugConstructor(CLASS_NAME,
                            new String[]
                            {
                              String.valueOf(matchingRule),
                              String.valueOf(names),
                              String.valueOf(description),
                              String.valueOf(isObsolete),
                              String.valueOf(attributes),
                              String.valueOf(extraProperties)
                            });
    assert debugConstructor(CLASS_NAME, String.valueOf(definition),
                            String.valueOf(matchingRule),
                            String.valueOf(names),
                            String.valueOf(description),
                            String.valueOf(isObsolete),
                            String.valueOf(attributes),
                            String.valueOf(extraProperties));
    ensureNotNull(definition, matchingRule);
    this.definition   = definition;
    this.matchingRule = matchingRule;
    this.description  = description;
    this.isObsolete   = isObsolete;
    if ((names == null) || names.isEmpty())
    {
      this.names = new LinkedHashMap<String,String>(0);
    }
    else
    {
      this.names = new LinkedHashMap<String,String>(names);
    }
    if ((attributes == null) || attributes.isEmpty())
    {
      this.attributes = new LinkedHashSet<AttributeType>(0);
    }
    else
    {
      this.attributes = new LinkedHashSet<AttributeType>(attributes);
    }
    if ((extraProperties == null) || extraProperties.isEmpty())
    {
      this.extraProperties =
           new LinkedHashMap<String,List<String>>(0);
    }
    else
    {
      this.extraProperties =
           new LinkedHashMap<String,List<String>>(extraProperties);
    }
  }
    this.matchingRule    = matchingRule;
    this.names           = names;
    this.description     = description;
    this.isObsolete      = isObsolete;
    this.attributes      = attributes;
    this.schemaFile      = null;
    this.extraProperties = extraProperties;
  /**
   * Retrieves the definition string used to create this matching rule
   * use.
   *
   * @return  The definition string used to create this matching rule
   *          use.
   */
  public String getDefinition()
  {
    assert debugEnter(CLASS_NAME, "getDefinition");
    return definition;
  }
  /**
   * Creates a new instance of this matching rule use based on the
   * definition string.  It will also preserve other state information
   * associated with this matching rule use that is not included in
   * the definition string (e.g., the name of the schema file with
   * which it is associated).
   *
   * @return  The new instance of this matching rule use based on the
   *          definition string.
   *
   * @throws  DirectoryException  If a problem occurs while attempting
   *                              to create a new matching rule use
   *                              instance from the definition string.
   */
  public MatchingRuleUse recreateFromDefinition()
         throws DirectoryException
  {
    ByteString value  = ByteStringFactory.create(definition);
    Schema     schema = DirectoryConfig.getSchema();
    MatchingRuleUse mru =
         MatchingRuleUseSyntax.decodeMatchingRuleUse(value, schema);
    mru.setSchemaFile(getSchemaFile());
    return mru;
  }
@@ -149,29 +224,13 @@
  /**
   * Specifies the matching rule for this matching rule use.
   *
   * @param  matchingRule  The matching rule for this matching rule
   *                       use.
   */
  public void setMatchingRule(MatchingRule matchingRule)
  {
    assert debugEnter(CLASS_NAME, "setMatchingRule",
                      String.valueOf(matchingRule));
    this.matchingRule = matchingRule;
  }
  /**
   * Retrieves the set of names for this matching rule use.  The
   * mapping will be between the names in all lowercase form and the
   * names in the user-defined form.
   *
   * @return  The set of names for this matching rule use.
   */
  public ConcurrentHashMap<String,String> getNames()
  public Map<String,String> getNames()
  {
    assert debugEnter(CLASS_NAME, "getNames");
@@ -185,7 +244,7 @@
   * rule use.
   *
   * @return  The primary name to use when referencing this matching
   *          rule use, or <CODE>null</CODE> if there is none.
   *          rule use, or {@code null} if there is none.
   */
  public String getName()
  {
@@ -209,8 +268,8 @@
   * @param  lowerName  The name for which to make the determination,
   *                    formatted in all lowercase characters.
   *
   * @return  <CODE>true</CODE> if this matching rule use has the
   *          specified name, or <CODE>false</CODE> if not.
   * @return  {@code true} if this matching rule use has the specified
   *          name, or {@code false} if not.
   */
  public boolean hasName(String lowerName)
  {
@@ -223,69 +282,25 @@
  /**
   * Specifies the set of names for this matching rule use as a
   * mapping between the names in all lowercase form and the names in
   * the user-defined form.
   *
   * @param  names  The set of names for this matching rule use.
   */
  public void setNames(ConcurrentHashMap<String,String> names)
  {
    assert debugEnter(CLASS_NAME, "setNames", String.valueOf(names));
    this.names = names;
  }
  /**
   * Adds the provided name to the set of names for this matching rule
   * use.
   *
   * @param  name  The name to add to the set of names for this
   *               matching rule use.
   */
  public void addName(String name)
  {
    assert debugEnter(CLASS_NAME, "addName", String.valueOf(name));
    names.put(toLowerCase(name), name);
  }
  /**
   * Removes the provided name from the set of names for this matching
   * rule use.  This will have no effect if the specified name is not
   * associated with this matching rule use.
   *
   * @param  lowerName  The name to remove from the set of names for
   *                    this matching rule use, in all lowercase
   *                    characters.
   */
  public void removeName(String lowerName)
  {
    assert debugEnter(CLASS_NAME, "removeName",
                      String.valueOf(lowerName));
    names.remove(lowerName);
  }
  /**
   * Retrieves the path to the schema file that contains the
   * definition for this matching rule use.
   *
   * @return  The path to the schema file that contains the definition
   *          for this matching rule use, or <CODE>null</CODE> if it
   *          is not known or if it is not stored in any schema file.
   *          for this matching rule use, or {@code null} if it is not
   *          known or if it is not stored in any schema file.
   */
  public String getSchemaFile()
  {
    assert debugEnter(CLASS_NAME, "getSchemaFile");
    return schemaFile;
    List<String> values =
         extraProperties.get(SCHEMA_PROPERTY_FILENAME);
    if ((values == null) || values.isEmpty())
    {
      return null;
    }
    return values.get(0);
  }
@@ -302,7 +317,7 @@
    assert debugEnter(CLASS_NAME, "setSchemaFile",
                      String.valueOf(schemaFile));
    this.schemaFile = schemaFile;
    setExtraProperty(SCHEMA_PROPERTY_FILENAME, schemaFile);
  }
@@ -311,7 +326,7 @@
   * Retrieves the description for this matching rule use.
   *
   * @return  The description for this matching rule use, or
   *          <CODE>null</CODE> if there is none.
   *          {@code null} if there is none.
   */
  public String getDescription()
  {
@@ -323,25 +338,10 @@
  /**
   * Specifies the description for this matching rule use.
   *
   * @param  description  The description for this matching rule use.
   */
  public void setDescription(String description)
  {
    assert debugEnter(CLASS_NAME, "setDescription",
                      String.valueOf(description));
    this.description = description;
  }
  /**
   * Indicates whether this matching rule use is declared "obsolete".
   *
   * @return  <CODE>true</CODE> if this matching rule use is declared
   *          "obsolete", or <CODE>false</CODE> if it is not.
   * @return  {@code true} if this matching rule use is declared
   *          "obsolete", or {@code false} if it is not.
   */
  public boolean isObsolete()
  {
@@ -353,29 +353,13 @@
  /**
   * Specifies whether this matching rule use is declared "obsolete".
   *
   * @param  isObsolete  Specifies whether this matching rule use is
   *                     declared "obsolete".
   */
  public void setObsolete(boolean isObsolete)
  {
    assert debugEnter(CLASS_NAME, "setObsolete",
                      String.valueOf(isObsolete));
    this.isObsolete = isObsolete;
  }
  /**
   * Retrieves the set of attributes associated with this matching
   * rule use.
   *
   * @return  The set of attributes associated with this matching
   *          rule use.
   */
  public CopyOnWriteArraySet<AttributeType> getAttributes()
  public Set<AttributeType> getAttributes()
  {
    assert debugEnter(CLASS_NAME, "getAttributes");
@@ -391,9 +375,9 @@
   * @param  attributeType  The attribute type for which to make the
   *                        determination.
   *
   * @return  <CODE>true</CODE> if the provided attribute type is
   *          referenced by this matching rule use, or
   *          <CODE>false</CODE> if it is not.
   * @return  {@code true} if the provided attribute type is
   *          referenced by this matching rule use, or {@code false}
   *          if it is not.
   */
  public boolean appliesToAttribute(AttributeType attributeType)
  {
@@ -406,71 +390,15 @@
  /**
   * Specifies the set of attributes for this matching rule use.
   *
   * @param  attributes  The set of attributes for this matching rule
   *                     use.
   */
  public void setAttributes(
                   CopyOnWriteArraySet<AttributeType> attributes)
  {
    assert debugEnter(CLASS_NAME, "setAttributes",
                      String.valueOf(attributes));
    this.attributes = attributes;
  }
  /**
   * Adds the provided attribute type to the set of attributes for
   * this matching rule use.  This will have no effect if the provided
   * attribute type is already associated with this matching rule use.
   *
   * @param  attributeType  The attribute type to add to the set of
   *                        attributes for this matching rule use.
   */
  public void addAttribute(AttributeType attributeType)
  {
    assert debugEnter(CLASS_NAME, "addAttribute",
                      String.valueOf(attributeType));
    attributes.add(attributeType);
  }
  /**
   * Removes the provided attribute type from the set of attributes
   * for this matching rule use.  This will have no effect if the
   * provided attribute type is not associated with this matching rule
   * use.
   *
   * @param  attributeType  The attribute type to remove from the set
   *                        of attributes for this matching rule use.
   */
  public void removeAttribute(AttributeType attributeType)
  {
    assert debugEnter(CLASS_NAME, "addAttribute",
                      String.valueOf(attributeType));
    attributes.remove(attributeType);
  }
  /**
   * Retrieves a mapping between the names of any extra non-standard
   * properties that may be associated with this matching rule use and
   * the value for that property.  The caller may alter the contents
   * of this mapping.
   * the value for that property.
   *
   * @return  A mapping between the names of any extra non-standard
   *          properties that may be associated with this matching
   *          rule use and the value for that property.
   */
  public ConcurrentHashMap<String,CopyOnWriteArrayList<String>>
              getExtraProperties()
  public Map<String,List<String>> getExtraProperties()
  {
    assert debugEnter(CLASS_NAME, "getExtraProperties");
@@ -487,11 +415,10 @@
   *                       to retrieve the value.
   *
   * @return  The value of the specified "extra" property for this
   *          matching rule use, or <CODE>null</CODE> if no such
   *          property is defined.
   *          matching rule use, or {@code null} if no such property
   *          is defined.
   */
  public CopyOnWriteArrayList<String>
              getExtraProperty(String propertyName)
  public List<String> getExtraProperty(String propertyName)
  {
    assert debugEnter(CLASS_NAME, "getExtraProperty",
                      String.valueOf(propertyName));
@@ -502,14 +429,74 @@
  /**
   * Specifies the provided "extra" property for this matching rule
   * use.
   *
   * @param  name   The name for the "extra" property.  It must not be
   *                {@code null}.
   * @param  value  The value for the "extra" property, or
   *                {@code null} if the property is to be removed.
   */
  public void setExtraProperty(String name, String value)
  {
    assert debugEnter(CLASS_NAME, "setExtraProperty",
                      String.valueOf(name), String.valueOf(value));
    ensureNotNull(name);
    if (value == null)
    {
      extraProperties.remove(name);
    }
    else
    {
      LinkedList<String> values = new LinkedList<String>();
      values.add(value);
      extraProperties.put(name, values);
    }
  }
  /**
   * Specifies the provided "extra" property for this matching rule
   * use.
   *
   * @param  name    The name for the "extra" property.  It must not
   *                 be {@code null}.
   * @param  values  The set of value for the "extra" property, or
   *                 {@code null} if the property is to be removed.
   */
  public void setExtraProperty(String name, List<String> values)
  {
    assert debugEnter(CLASS_NAME, "setExtraProperty",
                      String.valueOf(name), String.valueOf(values));
    ensureNotNull(name);
    if ((values == null) || values.isEmpty())
    {
      extraProperties.remove(name);
    }
    else
    {
      LinkedList<String> valuesCopy = new LinkedList<String>(values);
      extraProperties.put(name, valuesCopy);
    }
  }
  /**
   * Indicates whether the provided object is equal to this matching
   * rule use.  The object will be considered equal if it is a
   * matching rule use with the same matching rule.
   *
   * @param  o  The object for which to make the determination.
   *
   * @return  <CODE>true</CODE> if the provided object is equal to
   *          this matching rule use, or <CODE>false</CODE> if not.
   * @return  {@code true} if the provided object is equal to this
   *          matching rule use, or {@code false} if not.
   */
  public boolean equals(Object o)
  {
@@ -647,8 +634,13 @@
    {
      for (String property : extraProperties.keySet())
      {
        CopyOnWriteArrayList<String> valueList =
             extraProperties.get(property);
        if ((! includeFileElement) &&
            property.equals(SCHEMA_PROPERTY_FILENAME))
        {
          continue;
        }
        List<String> valueList = extraProperties.get(property);
        buffer.append(" ");
        buffer.append(property);
@@ -675,16 +667,6 @@
      }
    }
    if (includeFileElement && (schemaFile != null) &&
        (! extraProperties.containsKey(SCHEMA_PROPERTY_FILENAME)))
    {
      buffer.append(" ");
      buffer.append(SCHEMA_PROPERTY_FILENAME);
      buffer.append(" '");
      buffer.append(schemaFile);
      buffer.append("'");
    }
    buffer.append(" )");
  }
}
opendj-sdk/opends/src/server/org/opends/server/types/NameForm.java
@@ -22,20 +22,26 @@
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2006 Sun Microsystems, Inc.
 *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
 */
package org.opends.server.types;
import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.opends.server.schema.NameFormSyntax;
import static org.opends.server.loggers.Debug.*;
import static org.opends.server.util.ServerConstants.*;
import static org.opends.server.util.StaticUtils.*;
import static org.opends.server.util.Validator.*;
@@ -45,7 +51,8 @@
 * and/or may be used in the RDN of an entry with a given structural
 * objectclass.
 */
public class NameForm
public final class NameForm
       implements SchemaFileElement
{
  /**
   * The fully-qualified name of this class for debugging purposes.
@@ -56,49 +63,52 @@
  // Indicates whether this name form is declared "obsolete".
  private boolean isObsolete;
  private final boolean isObsolete;
  // The set of additional name-value pairs associated with this name
  // form definition.
  private ConcurrentHashMap<String,CopyOnWriteArrayList<String>>
               extraProperties;
  private final Map<String,List<String>> extraProperties;
  // The mapping between the lowercase names and the user-provided
  // names for this name form.
  private ConcurrentHashMap<String,String> names;
  // The set of optional attribute types for this name form.
  private CopyOnWriteArraySet<AttributeType> optionalAttributes;
  // The set of required attribute types for this name form.
  private CopyOnWriteArraySet<AttributeType> requiredAttributes;
  private final Map<String,String> names;
  // The reference to the structural objectclass for this name form.
  private ObjectClass structuralClass;
  private final ObjectClass structuralClass;
  // The set of optional attribute types for this name form.
  private final Set<AttributeType> optionalAttributes;
  // The set of required attribute types for this name form.
  private final Set<AttributeType> requiredAttributes;
  // The definition string used to create this name form.
  private final String definition;
  // The description for this name form.
  private String description;
  private final String description;
  // The OID for this name form.
  private String oid;
  // The path to the schema file that contains the definition for this
  // name form.
  private String schemaFile;
  private final String oid;
  /**
   * Creates a new name form definition with the provided information.
   *
   * @param  definition          The definition string used to create
   *                             this name form.  It must not be
   *                             {@code null}.
   * @param  names               The set of names that may be used to
   *                             reference this name form.
   * @param  oid                 The OID for this name form.
   * @param  oid                 The OID for this name form.  It must
   *                             not be {@code null}.
   * @param  description         The description for this name form.
   * @param  isObsolete          Indicates whether this name form is
   *                             declared "obsolete".
   * @param  structuralClass     The structural objectclass with which
   *                             this name form is associated.
   *                             this name form is associated.  It
   *                             must not be {@code null}.
   * @param  requiredAttributes  The set of required attribute types
   *                             for this name form.
   * @param  optionalAttributes  The set of optional attribute types
@@ -106,36 +116,111 @@
   * @param  extraProperties     A set of extra properties for this
   *                             name form.
   */
  public NameForm(ConcurrentHashMap<String,String> names, String oid,
              String description, boolean isObsolete,
              ObjectClass structuralClass,
              CopyOnWriteArraySet<AttributeType> requiredAttributes,
              CopyOnWriteArraySet<AttributeType> optionalAttributes,
              ConcurrentHashMap<String,CopyOnWriteArrayList<String>>
                   extraProperties)
  public NameForm(String definition, Map<String,String> names,
                  String oid, String description, boolean isObsolete,
                  ObjectClass structuralClass,
                  Set<AttributeType> requiredAttributes,
                  Set<AttributeType> optionalAttributes,
                  Map<String,List<String>> extraProperties)
  {
    assert debugConstructor(CLASS_NAME,
                            new String[]
                            {
                              String.valueOf(names),
                              String.valueOf(oid),
                              String.valueOf(description),
                              String.valueOf(isObsolete),
                              String.valueOf(structuralClass),
                              String.valueOf(requiredAttributes),
                              String.valueOf(optionalAttributes),
                              String.valueOf(extraProperties)
                            });
    assert debugConstructor(CLASS_NAME, String.valueOf(definition),
                            String.valueOf(names),
                            String.valueOf(oid),
                            String.valueOf(description),
                            String.valueOf(isObsolete),
                            String.valueOf(structuralClass),
                            String.valueOf(requiredAttributes),
                            String.valueOf(optionalAttributes),
                            String.valueOf(extraProperties));
    this.names              = names;
    this.oid                = oid;
    this.description        = description;
    this.isObsolete         = isObsolete;
    this.structuralClass    = structuralClass;
    this.requiredAttributes = requiredAttributes;
    this.optionalAttributes = optionalAttributes;
    this.schemaFile         = null;
    this.extraProperties    = extraProperties;
    ensureNotNull(definition, oid, structuralClass);
    this.definition      = definition;
    this.oid             = oid;
    this.description     = description;
    this.isObsolete      = isObsolete;
    this.structuralClass = structuralClass;
    if ((names == null) || names.isEmpty())
    {
      this.names = new LinkedHashMap<String,String>(0);
    }
    else
    {
      this.names = new LinkedHashMap<String,String>(names);
    }
    if ((requiredAttributes == null) || requiredAttributes.isEmpty())
    {
      this.requiredAttributes = new LinkedHashSet<AttributeType>(0);
    }
    else
    {
      this.requiredAttributes =
           new LinkedHashSet<AttributeType>(requiredAttributes);
    }
    if ((optionalAttributes == null) || optionalAttributes.isEmpty())
    {
      this.optionalAttributes = new LinkedHashSet<AttributeType>(0);
    }
    else
    {
      this.optionalAttributes =
           new LinkedHashSet<AttributeType>(optionalAttributes);
    }
    if ((extraProperties == null) || extraProperties.isEmpty())
    {
      this.extraProperties =
           new LinkedHashMap<String,List<String>>(0);
    }
    else
    {
      this.extraProperties =
           new LinkedHashMap<String,List<String>>(extraProperties);
    }
  }
  /**
   * Retrieves the definition string used to create this name form.
   *
   * @return  The definition string used to create this name form.
   */
  public String getDefinition()
  {
    assert debugEnter(CLASS_NAME, "getDefinition");
    return definition;
  }
  /**
   * Creates a new instance of this name form based on the definition
   * string.  It will also preserve other state information associated
   * with this name form that is not included in the definition string
   * (e.g., the name of the schema file with which it is associated).
   *
   * @return  The new instance of this name form based on the
   *          definition string.
   *
   * @throws  DirectoryException  If a problem occurs while attempting
   *                              to create a new name form instance
   *                              from the definition string.
   */
  public NameForm recreateFromDefinition()
         throws DirectoryException
  {
    ByteString value  = ByteStringFactory.create(definition);
    Schema     schema = DirectoryConfig.getSchema();
    NameForm nf = NameFormSyntax.decodeNameForm(value, schema);
    nf.setSchemaFile(getSchemaFile());
    return nf;
  }
@@ -149,7 +234,7 @@
   * @return  The set of names that may be used to reference this
   *          name form.
   */
  public ConcurrentHashMap<String,String> getNames()
  public Map<String,String> getNames()
  {
    assert debugEnter(CLASS_NAME, "getNames");
@@ -159,33 +244,14 @@
  /**
   * Specifies the set of names that may be used to reference this
   * name form.  The provided set must provide a mapping between each
   * name in all lowercase characters and that name in a user-defined
   * form (which may include mixed capitalization).
   *
   * @param  names  The set of names that may be used to reference
   *                this name form.
   */
  public void setNames(ConcurrentHashMap<String,String> names)
  {
    assert debugEnter(CLASS_NAME, "setNames", String.valueOf(names));
    this.names = names;
  }
  /**
   * Indicates whether the provided lowercase name may be used to
   * reference this name form.
   *
   * @param  lowerName  The name for which to make the determination,
   *                    in all lowercase characters.
   *
   * @return  <CODE>true</CODE> if the provided lowercase name may be
   *          used to reference this name form, or <CODE>false</CODE>
   *          if not.
   * @return  {@code true} if the provided lowercase name may be used
   *          to reference this name form, or {@code false} if not.
   */
  public boolean hasName(String lowerName)
  {
@@ -198,41 +264,6 @@
  /**
   * Adds the provided name to the set of names that may be used to
   * reference this name form.
   *
   * @param  name  The name to add to the set of names that may be
   *               used to reference this name form.
   */
  public void addName(String name)
  {
    assert debugEnter(CLASS_NAME, "addName", String.valueOf(name));
    String lowerName = toLowerCase(name);
    names.put(lowerName, name);
  }
  /**
   * Removes the provided lowercase name from the set of names that
   * may be used to reference this name form.
   *
   * @param  lowerName  The name to remove from the set of names that
   *                    may be used to reference this name form, in
   *                    all lowercase characters.
   */
  public void removeName(String lowerName)
  {
    assert debugEnter(CLASS_NAME, "removeName",
                      String.valueOf(lowerName));
    names.remove(lowerName);
  }
  /**
   * Retrieves the OID for this name form.
   *
   * @return  The OID for this name form.
@@ -247,20 +278,6 @@
  /**
   * Specifies the OID for this name form.
   *
   * @param  oid  The OID for this name form.
   */
  public void setOID(String oid)
  {
    assert debugEnter(CLASS_NAME, "setOID", String.valueOf(oid));
    this.oid = oid;
  }
  /**
   * Retrieves the name or OID that should be used to reference this
   * name form.  If at least one name is defined, then the first will
   * be returned.  Otherwise, the OID will be returned.
@@ -292,9 +309,9 @@
   * @param  lowerValue  The value, in all lowercase characters, that
   *                     may be used to make the determination.
   *
   * @return  <CODE>true</CODE> if the provided lowercase value is one
   *          of the names or the OID of this name form, or
   *          <CODE>false</CODE> if it is not.
   * @return  {@code true} if the provided lowercase value is one of
   *          the names or the OID of this name form, or {@code false}
   *          if it is not.
   */
  public boolean hasNameOrOID(String lowerValue)
  {
@@ -316,14 +333,21 @@
   * definition for this name form.
   *
   * @return  The path to the schema file that contains the definition
   *          for this name form, or <CODE>null</CODE> if it is not
   *          known or if it is not stored in any schema file.
   *          for this name form, or {@code null} if it is not known
   *          or if it is not stored in any schema file.
   */
  public String getSchemaFile()
  {
    assert debugEnter(CLASS_NAME, "getSchemaFile");
    return schemaFile;
    List<String> values =
         extraProperties.get(SCHEMA_PROPERTY_FILENAME);
    if ((values == null) || values.isEmpty())
    {
      return null;
    }
    return values.get(0);
  }
@@ -340,7 +364,7 @@
    assert debugEnter(CLASS_NAME, "setSchemaFile",
                      String.valueOf(schemaFile));
    this.schemaFile = schemaFile;
    setExtraProperty(SCHEMA_PROPERTY_FILENAME, schemaFile);
  }
@@ -348,8 +372,8 @@
  /**
   * Retrieves the description for this name form.
   *
   * @return  The description for this name form, or <CODE>null</CODE>
   *          if there is none.
   * @return  The description for this name form, or {@code true} if
   *          there is none.
   */
  public String getDescription()
  {
@@ -361,21 +385,6 @@
  /**
   * Specifies the description for this name form.
   *
   * @param  description  The description for this name form.
   */
  public void setDescription(String description)
  {
    assert debugEnter(CLASS_NAME, "setDescription",
                      String.valueOf(description));
    this.description = description;
  }
  /**
   * Retrieves the reference to the structural objectclass for this
   * name form.
   *
@@ -392,27 +401,11 @@
  /**
   * Specifies the structural objectclass for this name form.
   *
   * @param  structuralClass  The structural objectclass for this name
   *                          form.
   */
  public void setStructuralClass(ObjectClass structuralClass)
  {
    assert debugEnter(CLASS_NAME, "setStructuralClass",
                      String.valueOf(structuralClass));
    this.structuralClass = structuralClass;
  }
  /**
   * Retrieves the set of required attributes for this name form.
   *
   * @return  The set of required attributes for this name form.
   */
  public CopyOnWriteArraySet<AttributeType> getRequiredAttributes()
  public Set<AttributeType> getRequiredAttributes()
  {
    assert debugEnter(CLASS_NAME, "getRequiredAttributes");
@@ -428,9 +421,8 @@
   * @param  attributeType  The attribute type for which to make the
   *                        determination.
   *
   * @return  <CODE>true</CODE> if the provided attribute type is
   *          required by this name form, or <CODE>false</CODE> if
   *          not.
   * @return  {@code true} if the provided attribute type is required
   *          by this name form, or {@code false} if not.
   */
  public boolean isRequired(AttributeType attributeType)
  {
@@ -443,62 +435,11 @@
  /**
   * Specifies the set of required attributes for this name form.
   *
   * @param  requiredAttributes  The set of required attributes for
   *                             this name form.
   */
  public void setRequiredAttributes(CopyOnWriteArraySet<AttributeType>
                                         requiredAttributes)
  {
    assert debugEnter(CLASS_NAME, "setRequiredAttributes",
                      String.valueOf(requiredAttributes));
    this.requiredAttributes = requiredAttributes;
  }
  /**
   * Adds the provided attribute to the set of required attributes for
   * this name form.
   *
   * @param  attributeType  The attribute type to add to the set of
   *                        required attributes for this name form.
   */
  public void addRequiredAttribute(AttributeType attributeType)
  {
    assert debugEnter(CLASS_NAME, "addRequiredAttribute",
                      String.valueOf(attributeType));
    requiredAttributes.add(attributeType);
  }
  /**
   * Removes the provided attribute from the set of required
   * attributes for this name form.
   *
   * @param  attributeType  The attribute type to remove from the set
   *                        of required attributes for this name form.
   */
  public void removeRequiredAttribute(AttributeType attributeType)
  {
    assert debugEnter(CLASS_NAME, "removeRequiredAttribute",
                      String.valueOf(attributeType));
    requiredAttributes.remove(attributeType);
  }
  /**
   * Retrieves the set of optional attributes for this name form.
   *
   * @return  The set of optional attributes for this name form.
   */
  public CopyOnWriteArraySet<AttributeType> getOptionalAttributes()
  public Set<AttributeType> getOptionalAttributes()
  {
    assert debugEnter(CLASS_NAME, "getOptionalAttributes");
@@ -514,9 +455,8 @@
   * @param  attributeType  The attribute type for which to make the
   *                        determination.
   *
   * @return  <CODE>true</CODE> if the provided attribute type is
   *          optional for this name form, or <CODE>false</CODE> if
   *          not.
   * @return  {@code true} if the provided attribute type is optional
   *          for this name form, or {@code false} if not.
   */
  public boolean isOptional(AttributeType attributeType)
  {
@@ -529,66 +469,15 @@
  /**
   * Specifies the set of optional attributes for this name form.
   *
   * @param  optionalAttributes  The set of optional attributes for
   *                             this name form.
   */
  public void setOptionalAttributes(CopyOnWriteArraySet<AttributeType>
                                         optionalAttributes)
  {
    assert debugEnter(CLASS_NAME, "setOptionalAttributes",
                      String.valueOf(optionalAttributes));
    this.optionalAttributes = optionalAttributes;
  }
  /**
   * Adds the provided attribute to the set of optional attributes for
   * this name form.
   *
   * @param  attributeType  The attribute type to add to the set of
   *                        optional attributes for this name form.
   */
  public void addOptionalAttribute(AttributeType attributeType)
  {
    assert debugEnter(CLASS_NAME, "addOptionalAttribute",
                      String.valueOf(attributeType));
    optionalAttributes.add(attributeType);
  }
  /**
   * Removes the provided attribute from the set of optional
   * attributes for this name form.
   *
   * @param  attributeType  The attribute type to remove from the set
   *                        optional attributes for this name form.
   */
  public void removeOptionalAttribute(AttributeType attributeType)
  {
    assert debugEnter(CLASS_NAME, "removeOptionalAttribute",
                      String.valueOf(attributeType));
    optionalAttributes.remove(attributeType);
  }
  /**
   * Indicates whether the provided attribute type is in the list of
   * required or optional attributes for this name form.
   *
   * @param  attributeType  The attribute type for which to make the
   *                        determination.
   *
   * @return  <CODE>true</CODE> if the provided attribute type is
   *          required or allowed for this name form, or
   *          <CODE>false</CODE> if it is not.
   * @return  {@code true} if the provided attribute type is required
   *          or optional for this name form, or {@code false} if it
   *          is not.
   */
  public boolean isRequiredOrOptional(AttributeType attributeType)
  {
@@ -604,8 +493,8 @@
  /**
   * Indicates whether this name form is declared "obsolete".
   *
   * @return  <CODE>true</CODE> if this name form is declared
   *          "obsolete", or <CODE>false</CODE> if it is not.
   * @return  {@code true} if this name form is declared
   *          "obsolete", or {@code false} if it is not.
   */
  public boolean isObsolete()
  {
@@ -617,33 +506,15 @@
  /**
   * Specifies whether this name form is declared "obsolete".
   *
   * @param  isObsolete  Specifies whether this name form is declared
   *                     "obsolete".
   */
  public void setObsolete(boolean isObsolete)
  {
    assert debugEnter(CLASS_NAME, "setObsolete",
                      String.valueOf(isObsolete));
    this.isObsolete = isObsolete;
  }
  /**
   * Retrieves a mapping between the names of any extra non-standard
   * properties that may be associated with this name form and the
   * value for that property.  The caller may alter the contents of
   * this mapping.
   * value for that property.
   *
   * @return  A mapping between the names of any extra non-standard
   *          properties that may be associated with this name form
   *          and the value for that property.
   */
  public ConcurrentHashMap<String,CopyOnWriteArrayList<String>>
              getExtraProperties()
  public Map<String,List<String>> getExtraProperties()
  {
    assert debugEnter(CLASS_NAME, "getExtraProperties");
@@ -660,11 +531,10 @@
   *                       to retrieve the value.
   *
   * @return  The value of the specified "extra" property for this
   *          name form, or <CODE>null</CODE> if no such property is
   *          name form, or {@code null} if no such property is
   *          defined.
   */
  public CopyOnWriteArrayList<String>
              getExtraProperty(String propertyName)
  public List<String> getExtraProperty(String propertyName)
  {
    assert debugEnter(CLASS_NAME, "getExtraProperty",
                      String.valueOf(propertyName));
@@ -675,14 +545,72 @@
  /**
   * Specifies the provided "extra" property for this name form.
   *
   * @param  name   The name for the "extra" property.  It must not be
   *                {@code null}.
   * @param  value  The value for the "extra" property, or
   *                {@code null} if the property is to be removed.
   */
  public void setExtraProperty(String name, String value)
  {
    assert debugEnter(CLASS_NAME, "setExtraProperty",
                      String.valueOf(name), String.valueOf(value));
    ensureNotNull(name);
    if (value == null)
    {
      extraProperties.remove(name);
    }
    else
    {
      LinkedList<String> values = new LinkedList<String>();
      values.add(value);
      extraProperties.put(name, values);
    }
  }
  /**
   * Specifies the provided "extra" property for this name form.
   *
   * @param  name    The name for the "extra" property.  It must not
   *                 be {@code null}.
   * @param  values  The set of value for the "extra" property, or
   *                 {@code null} if the property is to be removed.
   */
  public void setExtraProperty(String name, List<String> values)
  {
    assert debugEnter(CLASS_NAME, "setExtraProperty",
                      String.valueOf(name), String.valueOf(values));
    ensureNotNull(name);
    if ((values == null) || values.isEmpty())
    {
      extraProperties.remove(name);
    }
    else
    {
      LinkedList<String> valuesCopy = new LinkedList<String>(values);
      extraProperties.put(name, valuesCopy);
    }
  }
  /**
   * Indicates whether the provided object is equal to this name form.
   * The object will be considered equal if it is a name form with the
   * same OID as the current name form.
   *
   * @param  o  The object for which to make the determination.
   *
   * @return  <CODE>true</CODE> if the provided object is equal to
   *          this name form, or <CODE>false</CODE> if not.
   * @return  {@code true} if the provided object is equal to this
   *          name form, or {@code true} if not.
   */
  public boolean equals(Object o)
  {
@@ -861,8 +789,13 @@
    {
      for (String property : extraProperties.keySet())
      {
        CopyOnWriteArrayList<String> valueList =
             extraProperties.get(property);
        if ((! includeFileElement) &&
            property.equals(SCHEMA_PROPERTY_FILENAME))
        {
          continue;
        }
        List<String> valueList = extraProperties.get(property);
        buffer.append(" ");
        buffer.append(property);
@@ -889,16 +822,6 @@
      }
    }
    if (includeFileElement && (schemaFile != null) &&
        (! extraProperties.containsKey(SCHEMA_PROPERTY_FILENAME)))
    {
      buffer.append(" ");
      buffer.append(SCHEMA_PROPERTY_FILENAME);
      buffer.append(" '");
      buffer.append(schemaFile);
      buffer.append("'");
    }
    buffer.append(" )");
  }
}
opendj-sdk/opends/src/server/org/opends/server/types/ObjectClass.java
@@ -22,16 +22,12 @@
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2006 Sun Microsystems, Inc.
 *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
 */
package org.opends.server.types;
import static org.opends.server.loggers.Debug.debugConstructor;
import static org.opends.server.loggers.Debug.debugEnter;
import static org.opends.server.util.ServerConstants.*;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
@@ -41,6 +37,13 @@
import java.util.Map;
import java.util.Set;
import org.opends.server.schema.ObjectClassSyntax;
import static org.opends.server.loggers.Debug.debugConstructor;
import static org.opends.server.loggers.Debug.debugEnter;
import static org.opends.server.util.ServerConstants.*;
import static org.opends.server.util.Validator.*;
/**
@@ -58,7 +61,10 @@
 * fields are accessed via their getters or via the
 * {@link #toString()} methods.
 */
public final class ObjectClass extends CommonSchemaElements {
public final class ObjectClass
       extends CommonSchemaElements
       implements SchemaFileElement
{
  /**
   * The fully-qualified name of this class for debugging purposes.
   */
@@ -89,6 +95,9 @@
  // contain any attribute.
  private final boolean isExtensibleObject;
  // The definition string used to create this objectclass.
  private final String definition;
  /**
@@ -100,62 +109,65 @@
   * from the set of <code>names</code> will be used as the primary
   * name.
   *
   * @param definition
   *          The definition string used to create this objectclass.
   *          It must not be {@code null}.
   * @param primaryName
   *          The primary name for this objectclass, or
   *          <code>null</code> if there is no primary name.
   *          {@code null} if there is no primary name.
   * @param names
   *          The set of names that may be used to reference this
   *          objectclass, or <code>null</code> if there are no
   *          name.
   *          objectclass.
   * @param oid
   *          The OID for this objectclass (must not be
   *          <code>null</code>).
   *          The OID for this objectclass.  It must not be
   *          {@code null}.
   * @param description
   *          The description for this objectclass, or
   *          <code>null</code> if there is no description.
   *          The description for this objectclass, or {@code null} if
   *          there is no description.
   * @param superiorClass
   *          The superior class for this objectclass, or
   *          <code>null</code> if there is no superior object
   *          classes.
   *          The superior class for this objectclass, or {@code null}
   *          if there is no superior object class.
   * @param requiredAttributes
   *          The set of required attribute types for this
   *          objectclass, or <code>null</code> if there are no
   *          required attribute types.
   *          objectclass.
   * @param optionalAttributes
   *          The set of optional attribute types for this
   *          objectclass, or <code>null</code> if there are no
   *          optional attribute types.
   *          objectclass.
   * @param objectClassType
   *          The objectclass type for this objectclass, or
   *          <code>null</code> to default to structural.
   *          {@code null} to default to structural.
   * @param isObsolete
   *          Indicates whether this objectclass is declared
   *          "obsolete".
   * @param extraProperties
   *          A set of extra properties for this objectclass, or
   *          <code>null</code> if there are no extra properties.
   * @throws NullPointerException
   *           If the <code>oid</code> is <code>null</code>.
   *          A set of extra properties for this objectclass.
   */
  public ObjectClass(String primaryName, Collection<String> names,
      String oid, String description, ObjectClass superiorClass,
      Set<AttributeType> requiredAttributes,
      Set<AttributeType> optionalAttributes,
      ObjectClassType objectClassType, boolean isObsolete,
      Map<String, List<String>> extraProperties)
      throws NullPointerException {
  public ObjectClass(String definition, String primaryName,
                     Collection<String> names, String oid,
                     String description, ObjectClass superiorClass,
                     Set<AttributeType> requiredAttributes,
                     Set<AttributeType> optionalAttributes,
                     ObjectClassType objectClassType,
                     boolean isObsolete,
                     Map<String, List<String>> extraProperties)
  {
    super(primaryName, names, oid, description, isObsolete,
        extraProperties);
    assert debugConstructor(CLASS_NAME, String.valueOf(primaryName),
        String.valueOf(names), String.valueOf(oid), String
            .valueOf(description), String.valueOf(superiorClass),
        String.valueOf(requiredAttributes), String
            .valueOf(optionalAttributes), String
            .valueOf(objectClassType), String.valueOf(isObsolete),
        String.valueOf(extraProperties));
                            String.valueOf(names),
                            String.valueOf(oid),
                            String.valueOf(description),
                            String.valueOf(superiorClass),
                            String.valueOf(requiredAttributes),
                            String.valueOf(optionalAttributes),
                            String.valueOf(objectClassType),
                            String.valueOf(isObsolete),
                            String.valueOf(extraProperties));
    ensureNotNull(definition, oid);
    this.definition    = definition;
    this.superiorClass = superiorClass;
    // Set flag indicating whether or not this object class allows any
@@ -214,6 +226,49 @@
  /**
   * Retrieves the definition string used to create this objectclass.
   *
   * @return  The definition string used to create this objectclass.
   */
  public String getDefinition()
  {
    assert debugEnter(CLASS_NAME, "getDefinition");
    return definition;
  }
  /**
   * Creates a new instance of this objectclass based on the
   * definition string.  It will also preserve other state information
   * associated with this objectclass that is not included in the
   * definition string (e.g., the name of the schema file with which
   * it is associated).
   *
   * @return  The new instance of this objectclass based on the
   *          definition string.
   *
   * @throws  DirectoryException  If a problem occurs while attempting
   *                              to create a new objectclass instance
   *                              from the definition string.
   */
  public ObjectClass recreateFromDefinition()
         throws DirectoryException
  {
    ByteString value  = ByteStringFactory.create(definition);
    Schema     schema = DirectoryConfig.getSchema();
    ObjectClass oc = ObjectClassSyntax.decodeObjectClass(value,
                                                         schema);
    oc.setSchemaFile(getSchemaFile());
    return oc;
  }
  /**
   * Retrieves the reference to the superior class for this
   * objectclass.
   *
opendj-sdk/opends/src/server/org/opends/server/types/Schema.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2006 Sun Microsystems, Inc.
 *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
 */
package org.opends.server.types;
@@ -364,7 +364,7 @@
      // rather than the attribute type because otherwise it would use
      // a very expensive matching rule (OID first component match)
      // that would kill performance.
      String valueString = attributeType.toString();
      String valueString = attributeType.getDefinition();
      ASN1OctetString rawValue = new ASN1OctetString(valueString);
      ASN1OctetString normValue =
           new ASN1OctetString(toLowerCase(valueString));
@@ -401,7 +401,7 @@
      // rather than the attribute type because otherwise it would use
      // a very expensive matching rule (OID first component match)
      // that would kill performance.
      String valueString = attributeType.toString();
      String valueString = attributeType.getDefinition();
      ASN1OctetString rawValue = new ASN1OctetString(valueString);
      ASN1OctetString normValue =
           new ASN1OctetString(toLowerCase(valueString));
@@ -556,7 +556,7 @@
      // rather than the attribute type because otherwise it would use
      // a very expensive matching rule (OID first component match)
      // that would kill performance.
      String valueString = objectClass.toString();
      String valueString = objectClass.getDefinition();
      ASN1OctetString rawValue = new ASN1OctetString(valueString);
      ASN1OctetString normValue =
           new ASN1OctetString(toLowerCase(valueString));
@@ -592,7 +592,7 @@
      // rather than the attribute type because otherwise it would use
      // a very expensive matching rule (OID first component match)
      // that would kill performance.
      String valueString = objectClass.toString();
      String valueString = objectClass.getDefinition();
      ASN1OctetString rawValue = new ASN1OctetString(valueString);
      ASN1OctetString normValue =
           new ASN1OctetString(toLowerCase(valueString));
@@ -1821,7 +1821,7 @@
      // rather than the attribute type because otherwise it would use
      // a very expensive matching rule (OID first component match)
      // that would kill performance.
      String valueString = matchingRuleUse.toString();
      String valueString = matchingRuleUse.getDefinition();
      ASN1OctetString rawValue  = new ASN1OctetString(valueString);
      ASN1OctetString normValue =
           new ASN1OctetString(toLowerCase(valueString));
@@ -1853,7 +1853,7 @@
      // rather than the attribute type because otherwise it would use
      // a very expensive matching rule (OID first component match)
      // that would kill performance.
      String valueString = matchingRuleUse.toString();
      String valueString = matchingRuleUse.getDefinition();
      ASN1OctetString rawValue  = new ASN1OctetString(valueString);
      ASN1OctetString normValue =
           new ASN1OctetString(toLowerCase(valueString));
@@ -1989,7 +1989,7 @@
      // rather than the attribute type because otherwise it would use
      // a very expensive matching rule (OID first component match)
      // that would kill performance.
      String valueString = ditContentRule.toString();
      String valueString = ditContentRule.getDefinition();
      ASN1OctetString rawValue  = new ASN1OctetString(valueString);
      ASN1OctetString normValue =
           new ASN1OctetString(toLowerCase(valueString));
@@ -2021,7 +2021,7 @@
      // rather than the attribute type because otherwise it would use
      // a very expensive matching rule (OID first component match)
      // that would kill performance.
      String valueString = ditContentRule.toString();
      String valueString = ditContentRule.getDefinition();
      ASN1OctetString rawValue  = new ASN1OctetString(valueString);
      ASN1OctetString normValue =
           new ASN1OctetString(toLowerCase(valueString));
@@ -2234,7 +2234,7 @@
      // rather than the attribute type because otherwise it would use
      // a very expensive matching rule (OID first component match)
      // that would kill performance.
      String valueString = ditStructureRule.toString();
      String valueString = ditStructureRule.getDefinition();
      ASN1OctetString rawValue  = new ASN1OctetString(valueString);
      ASN1OctetString normValue =
           new ASN1OctetString(toLowerCase(valueString));
@@ -2269,7 +2269,7 @@
      // rather than the attribute type because otherwise it would use
      // a very expensive matching rule (OID first component match)
      // that would kill performance.
      String valueString = ditStructureRule.toString();
      String valueString = ditStructureRule.getDefinition();
      ASN1OctetString rawValue  = new ASN1OctetString(valueString);
      ASN1OctetString normValue =
           new ASN1OctetString(toLowerCase(valueString));
@@ -2496,7 +2496,7 @@
      // rather than the attribute type because otherwise it would use
      // a very expensive matching rule (OID first component match)
      // that would kill performance.
      String valueString = nameForm.toString();
      String valueString = nameForm.getDefinition();
      ASN1OctetString rawValue  = new ASN1OctetString(valueString);
      ASN1OctetString normValue =
           new ASN1OctetString(toLowerCase(valueString));
@@ -2531,7 +2531,7 @@
      // rather than the attribute type because otherwise it would use
      // a very expensive matching rule (OID first component match)
      // that would kill performance.
      String valueString = nameForm.toString();
      String valueString = nameForm.getDefinition();
      ASN1OctetString rawValue  = new ASN1OctetString(valueString);
      ASN1OctetString normValue =
           new ASN1OctetString(toLowerCase(valueString));
@@ -2542,6 +2542,244 @@
  /**
   * Recursively rebuilds all schema elements that are dependent upon
   * the provided element.  This must be invoked whenever an existing
   * schema element is modified in order to ensure that any elements
   * that depend on it should also be recreated to reflect the change.
   * <BR><BR>
   * The following conditions create dependencies between schema
   * elements:
   * <UL>
   *   <LI>If an attribute type references a superior attribute type,
   *       then it is dependent upon that superior attribute
   *       type.</LI>
   *   <LI>If an objectclass requires or allows an attribute type,
   *       then it is dependent upon that attribute type.</LI>
   *   <LI>If a name form requires or allows an attribute type in the
   *       RDN, then it is dependent upon that attribute type.</LI>
   *   <LI>If a DIT content rule requires, allows, or forbids the use
   *       of an attribute type, then it is dependent upon that
   *       attribute type.</LI>
   *   <LI>If a matching rule use references an attribute type, then
   *       it is dependent upon that attribute type.</LI>
   *   <LI>If an objectclass references a superior objectclass, then
   *       it is dependent upon that superior objectclass.</LI>
   *   <LI>If a name form references a structural objectclass, then it
   *       is dependent upon that objectclass.</LI>
   *   <LI>If a DIT content rule references a structural or auxiliary
   *       objectclass, then it is dependent upon that
   *       objectclass.</LI>
   *   <LI>If a DIT structure rule references a name form, then it is
   *       dependent upon that name form.</LI>
   *   <LI>If a DIT structure rule references a superior DIT structure
   *       rule, then it is dependent upon that superior DIT structure
   *       rule.</LI>
   * </UL>
   *
   * @param  element  The element for which to recursively rebuild all
   *                  dependent elements.
   *
   * @throws  DirectoryException  If a problem occurs while rebuilding
   *                              any of the schema elements.
   */
  public final void rebuildDependentElements(
                         SchemaFileElement element)
         throws DirectoryException
  {
    assert debugEnter(CLASS_NAME, "rebuildDependentElements",
                      String.valueOf(element));
    try
    {
      rebuildDependentElements(element, 0);
    }
    catch (DirectoryException de)
    {
      // If we got an error as a result of a circular reference, then
      // we want to make sure that the schema element we call out is
      // the one that is at the root of the problem.
      if (de.getErrorMessageID() ==
          MSGID_SCHEMA_CIRCULAR_DEPENDENCY_REFERENCE)
      {
        int    msgID   = MSGID_SCHEMA_CIRCULAR_DEPENDENCY_REFERENCE;
        String message = getMessage(msgID, element.getDefinition());
        throw new DirectoryException(de.getResultCode(), message,
                                     msgID, de);
      }
      // It wasn't a circular reference error, so just re-throw the
      // exception.
      throw de;
    }
  }
  /**
   * Recursively rebuilds all schema elements that are dependent upon
   * the provided element, increasing the depth for each level of
   * recursion to protect against errors due to circular references.
   *
   * @param  element  The element for which to recursively rebuild all
   *                  dependent elements.
   * @param  depth    The current recursion depth.
   *
   * @throws  DirectoryException  If a problem occurs while rebuilding
   *                              any of the schema elements.
   */
  private final void rebuildDependentElements(
                          SchemaFileElement element, int depth)
          throws DirectoryException
  {
    assert debugEnter(CLASS_NAME, "rebuildDependentElements",
                      String.valueOf(element), String.valueOf(depth));
    if (depth > 20)
    {
      // FIXME -- Is this an appropriate maximum depth for detecting
      // circular references?
      int    msgID   = MSGID_SCHEMA_CIRCULAR_DEPENDENCY_REFERENCE;
      String message = getMessage(msgID, element.getDefinition());
      throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM,
                                   message, msgID);
    }
    // Figure out what type of element we're dealing with and make the
    // appropriate determinations for that element.
    if (element instanceof AttributeType)
    {
      AttributeType t = (AttributeType) element;
      for (AttributeType at : attributeTypes.values())
      {
        if ((at.getSuperiorType() != null) &&
            at.getSuperiorType().equals(t))
        {
          AttributeType newAT = at.recreateFromDefinition();
          deregisterAttributeType(at);
          registerAttributeType(newAT, true);
          rebuildDependentElements(at, depth+1);
        }
      }
      for (ObjectClass oc : objectClasses.values())
      {
        if (oc.getRequiredAttributes().contains(t) ||
            oc.getOptionalAttributes().contains(t))
        {
          ObjectClass newOC = oc.recreateFromDefinition();
          deregisterObjectClass(oc);
          registerObjectClass(newOC, true);
          rebuildDependentElements(oc, depth+1);
        }
      }
      for (NameForm nf : nameFormsByOC.values())
      {
        if (nf.getRequiredAttributes().contains(t) ||
            nf.getOptionalAttributes().contains(t))
        {
          NameForm newNF = nf.recreateFromDefinition();
          deregisterNameForm(nf);
          registerNameForm(newNF, true);
          rebuildDependentElements(nf, depth+1);
        }
      }
      for (DITContentRule dcr : ditContentRules.values())
      {
        if (dcr.getRequiredAttributes().contains(t) ||
            dcr.getOptionalAttributes().contains(t) ||
            dcr.getProhibitedAttributes().contains(t))
        {
          DITContentRule newDCR = dcr.recreateFromDefinition();
          deregisterDITContentRule(dcr);
          registerDITContentRule(newDCR, true);
          rebuildDependentElements(dcr, depth+1);
        }
      }
      for (MatchingRuleUse mru : matchingRuleUses.values())
      {
        if (mru.getAttributes().contains(t))
        {
          MatchingRuleUse newMRU = mru.recreateFromDefinition();
          deregisterMatchingRuleUse(mru);
          registerMatchingRuleUse(newMRU, true);
          rebuildDependentElements(mru, depth+1);
        }
      }
    }
    else if (element instanceof ObjectClass)
    {
      ObjectClass c = (ObjectClass) element;
      for (ObjectClass oc : objectClasses.values())
      {
        if ((oc.getSuperiorClass() != null) &&
            oc.getSuperiorClass().equals(c))
        {
          ObjectClass newOC = oc.recreateFromDefinition();
          deregisterObjectClass(oc);
          registerObjectClass(newOC, true);
          rebuildDependentElements(oc, depth+1);
        }
      }
      NameForm nf = nameFormsByOC.get(c);
      if (nf != null)
      {
        NameForm newNF = nf.recreateFromDefinition();
        deregisterNameForm(nf);
        registerNameForm(newNF, true);
        rebuildDependentElements(nf, depth+1);
      }
      for (DITContentRule dcr : ditContentRules.values())
      {
        if (dcr.getStructuralClass().equals(c) ||
            dcr.getAuxiliaryClasses().contains(c))
        {
          DITContentRule newDCR = dcr.recreateFromDefinition();
          deregisterDITContentRule(dcr);
          registerDITContentRule(newDCR, true);
          rebuildDependentElements(dcr, depth+1);
        }
      }
    }
    else if (element instanceof NameForm)
    {
      NameForm n = (NameForm) element;
      DITStructureRule dsr = ditStructureRulesByNameForm.get(n);
      if (dsr != null)
      {
        DITStructureRule newDSR = dsr.recreateFromDefinition();
        deregisterDITStructureRule(dsr);
        registerDITStructureRule(newDSR, true);
        rebuildDependentElements(dsr, depth+1);
      }
    }
    else if (element instanceof DITStructureRule)
    {
      DITStructureRule d = (DITStructureRule) element;
      for (DITStructureRule dsr : ditStructureRulesByID.values())
      {
        if (dsr.getSuperiorRules().contains(d))
        {
          DITStructureRule newDSR = dsr.recreateFromDefinition();
          deregisterDITStructureRule(dsr);
          registerDITStructureRule(newDSR, true);
          rebuildDependentElements(dsr, depth+1);
        }
      }
    }
  }
  /**
   * Creates a new <CODE>Schema</CODE> object that is a duplicate of
   * this one.  It elements may be added and removed from the
   * duplicate without impacting this version.
opendj-sdk/opends/src/server/org/opends/server/types/SchemaFileElement.java
New file
@@ -0,0 +1,107 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying * information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2007 Sun Microsystems, Inc.
 */
package org.opends.server.types;
/**
 * This interface defines a set of methods that must be provided by a
 * schema file element, which is a schema element that is loaded from
 * a schema configuration file.
 * <BR><BR>
 * Note that this interface is not meant to be implemented by
 * third-party code, and only the following classes should be
 * considered schema file elements:
 * <UL>
 *   <LI>{@code org.opends.server.types.AttributeType}</LI>
 *   <LI>{@code org.opends.server.types.ObjectClass}</LI>
 *   <LI>{@code org.opends.server.types.NameForm}</LI>
 *   <LI>{@code org.opends.server.types.DITContentRule}</LI>
 *   <LI>{@code org.opends.server.types.DITStructureRule}</LI>
 *   <LI>{@code org.opends.server.types.MatchingRuleUse}</LI>
 * </UL>
 */
public interface SchemaFileElement
{
  /**
   * Retrieves the name of the schema file in which this element is
   * defined.
   *
   * @return  The name of the schema file in which this element is
   *          defined, or {@code null} if it is not known or this
   *          element is not defined in any schema file.
   */
  public String getSchemaFile();
  /**
   * Specifies the name of the schema file in which this element is
   * defined.
   *
   * @param  schemaFile  The name of the schema file in which this
   *                     element is defined, or {@code null} if it is
   *                     not defined in any schema file.
   */
  public void setSchemaFile(String schemaFile);
  /**
   * Retrieves the definition string that is used to represent this
   * element in the schema configuration file.
   *
   * @return  The definition string that should be used to represent
   *          this element in the schema configuration file.
   */
  public String getDefinition();
  /**
   * Creates a new instance of this schema element based on the
   * definition from the schema file.  The new instance should also
   * be created with all appropriate state information that may not
   * be directly represented in the schema definition (e.g., the name
   * of the schema file containing the definition).
   * <BR><BR>
   * Whenever an existing schema file element is modified with the
   * server online, this method will be invoked to recreate any
   * schema elements that might have been dependent upon the
   * modified element.
   *
   * @return  A new instance of this schema element based on the
   *          definition.
   *
   * @throws  DirectoryException  If a problem occurs while attempting
   *                              to create the new instance of this
   *                              schema element.
   */
  public SchemaFileElement recreateFromDefinition()
         throws DirectoryException;
}
opendj-sdk/opends/src/server/org/opends/server/util/ServerConstants.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2006 Sun Microsystems, Inc.
 *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
 */
package org.opends.server.util;
@@ -1396,6 +1396,55 @@
  /**
   * The description for the alert type that will be used for the alert
   * notification generated if a problem occurs while creating copies of the
   * existing schema configuration files and a problem occurs that leaves the
   * schema configuration in a potentially inconsistent state.
   */
  public static final String ALERT_DESCRIPTION_CANNOT_COPY_SCHEMA_FILES =
      "This alert type will be used to notify administrators if a problem " +
      "occurs while attempting to create copies of the existing schema " +
      "configuration files before making a schema update, and the schema " +
      "configuration is left in a potentially inconsistent state.";
  /**
   * The alert type string that will be used for the alert notification
   * generated if a problem occurs while creating copies of the existing schema
   * files in a manner that may leave the schema configuration inconsistent.
   */
  public static final String ALERT_TYPE_CANNOT_COPY_SCHEMA_FILES =
       "org.opends.server.CannotCopySchemaFiles";
  /**
   * The description for the alert type that will be used for the alert
   * notification generated if a problem occurs while writing new versions of
   * the server schema configuration files and a problem occurs that leaves the
   * schema configuration in a potentially inconsistent state.
   */
  public static final String ALERT_DESCRIPTION_CANNOT_WRITE_NEW_SCHEMA_FILES =
      "This alert type will be used to notify administrators if a problem " +
      "occurs while attempting to write new verisons of the server schema " +
      "configuration files, and the schema configuration is left in a " +
      "potentially inconsistent state.";
  /**
   * The alert type string that will be used for the alert notification
   * generated if a problem occurs while writing new versions of the server
   * schema files in a manner that may leave the schema configuration
   * inconsistent.
   */
  public static final String ALERT_TYPE_CANNOT_WRITE_NEW_SCHEMA_FILES =
       "org.opends.server.CannotWriteNewSchemaFiles";
  /**
   * The name of the default password storage scheme that will be used for new
   * passwords.
   */
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/backends/SchemaBackendTestCase.java
@@ -22,12 +22,14 @@
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2006 Sun Microsystems, Inc.
 *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
 */
package org.opends.server.backends;
import java.io.File;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
@@ -36,11 +38,14 @@
import org.testng.annotations.Test;
import org.opends.server.TestCaseUtils;
import org.opends.server.config.ConfigEntry;
import org.opends.server.config.ConfigException;
import org.opends.server.core.AddOperation;
import org.opends.server.core.DeleteOperation;
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.ModifyOperation;
import org.opends.server.core.ModifyDNOperation;
import org.opends.server.core.SchemaConfigManager;
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.protocols.internal.InternalSearchOperation;
import org.opends.server.tools.LDAPModify;
@@ -49,10 +54,17 @@
import org.opends.server.types.AttributeValue;
import org.opends.server.types.ByteStringFactory;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.DITContentRule;
import org.opends.server.types.DN;
import org.opends.server.types.Entry;
import org.opends.server.types.ExistingFileBehavior;
import org.opends.server.types.InitializationException;
import org.opends.server.types.LDIFExportConfig;
import org.opends.server.types.LDIFImportConfig;
import org.opends.server.types.MatchingRuleUse;
import org.opends.server.types.Modification;
import org.opends.server.types.ModificationType;
import org.opends.server.types.ObjectClass;
import org.opends.server.types.RDN;
import org.opends.server.types.ResultCode;
import org.opends.server.types.SearchFilter;
@@ -94,6 +106,23 @@
  /**
   * Tests the {@code initializeBackend} method by providing a null
   * configuration entry.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test(expectedExceptions = { ConfigException.class,
                               InitializationException.class })
  public void testInitializeWithNullEntry()
         throws Exception
  {
    SchemaBackend schemaBackend = new SchemaBackend();
    schemaBackend.initializeBackend(null, new DN[0]);
  }
  /**
   * Tests the {@code isLocal} method to ensure that it is considered local.
   */
  @Test()
@@ -443,6 +472,127 @@
  /**
   * Tests the behavior of the schema backend when attempting to add a new
   * attribute type that is not allowed to be altered.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testAddUnsupportedAttr()
         throws Exception
  {
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "add: objectClass",
         "objectClass: extensibleObject");
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    assertFalse(LDAPModify.mainModify(args, false, null, null) == 0);
  }
  /**
   * Tests the behavior of the schema backend when attempting to remove an
   * attribute type that is not allowed to be altered.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testRemoveUnsupportedAttr()
         throws Exception
  {
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "delete: objectClass",
         "objectClass: subschema",
         "-",
         "add: objectClass",
         "objectClass: extensibleObject");
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    assertFalse(LDAPModify.mainModify(args, false, null, null) == 0);
  }
  /**
   * Tests the behavior of the schema backend when attempting to remove all
   * attribute type definitions.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testRemoveAllAttributeTypes()
         throws Exception
  {
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "delete: attributeTypes");
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    assertFalse(LDAPModify.mainModify(args, false, null, null) == 0);
  }
  /**
   * Tests the behavior of the schema backend when attempting to replace all
   * attribute types.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testReplaceAllAttributeTypes()
         throws Exception
  {
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "replace: attributeTypes");
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    assertFalse(LDAPModify.mainModify(args, false, null, null) == 0);
  }
  /**
   * Tests the behavior of the schema backend when attempting to add a new
   * attribute type with a valid syntax and that isn't already defined.
   *
   * @throws  Exception  If an unexpected problem occurs.
@@ -455,10 +605,10 @@
         "dn: cn=schema",
         "changetype: modify",
         "add: attributeTypes",
         "attributeTypes: ( 1.3.6.1.4.1.26027.1.999.4 NAME " +
              "'testAddAttributeTypeSuccessful' SYNTAX " +
              "1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN " +
              "'SchemaBackendTestCase' )");
         "attributeTypes: ( 1.3.6.1.4.1.26027.1.999.4 " +
              "NAME 'testAddAttributeTypeSuccessful' " +
              "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE " +
              "X-ORGIN 'SchemaBackendTestCase' )");
    String attrName = "testaddattributetypesuccessful";
    assertFalse(DirectoryServer.getSchema().hasAttributeType(attrName));
@@ -493,10 +643,10 @@
         "dn: cn=schema",
         "changetype: modify",
         "add: attributeTypes",
         "attributeTypes: ( testaddattributetypesuccessfulnooid-oid NAME " +
              "'testAddAttributeTypeSuccessfulNoOID' SYNTAX " +
              "1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN " +
              "'SchemaBackendTestCase' )");
         "attributeTypes: ( testaddattributetypesuccessfulnooid-oid " +
              "NAME 'testAddAttributeTypeSuccessfulNoOID' " +
              "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE " +
              "X-ORGIN 'SchemaBackendTestCase' )");
    String attrName = "testaddattributetypesuccessfulnooid";
    assertFalse(DirectoryServer.getSchema().hasAttributeType(attrName));
@@ -518,6 +668,143 @@
  /**
   * Tests the behavior of the schema backend when attempting to add a new
   * attribute type to a specific schema file.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  public void testAddAttributeTypeToAltSchemaFile()
         throws Exception
  {
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "add: attributeTypes",
         "attributeTypes: ( testaddattributetypetoaltschemafile-oid " +
              "NAME 'testAddAttributeTypeToAltSchemaFile' " +
              "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE " +
              "X-ORIGIN 'SchemaBackendTestCase' " +
              "X-SCHEMA-FILE '98-schema-test-attrtype.ldif' )");
    String attrName = "testaddattributetypetoaltschemafile";
    assertFalse(DirectoryServer.getSchema().hasAttributeType(attrName));
    File schemaFile = new File(SchemaConfigManager.getSchemaDirectoryPath(),
                               "98-schema-test-attrtype.ldif");
    assertFalse(schemaFile.exists());
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    assertEquals(LDAPModify.mainModify(args, false, null, System.err), 0);
    assertTrue(DirectoryServer.getSchema().hasAttributeType(attrName));
    assertTrue(schemaFile.exists());
  }
  /**
   * Tests the behavior of the schema backend when attempting to add a new
   * attribute type in a manner that replaces an existing definition.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testAddAttributeTypeSuccessfulReplace()
         throws Exception
  {
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "add: attributeTypes",
         "attributeTypes: ( testaddattributetypesuccessfulreplace-oid " +
              "NAME 'testAddAttributeTypeSuccessfulReplace' " +
              "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE " +
              "X-ORIGIN 'SchemaBackendTestCase' )",
         "",
         "dn: cn=schema",
         "changetype: modify",
         "add: attributeTypes",
         "attributeTypes: ( testaddattributetypesuccessfulreplace-oid " +
              "NAME 'testAddAttributeTypeSuccessfulReplace' " +
              "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE " +
              "X-ORIGIN 'SchemaBackendTestCase' )");
    String attrName = "testaddattributetypesuccessfulreplace";
    assertFalse(DirectoryServer.getSchema().hasAttributeType(attrName));
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    assertEquals(LDAPModify.mainModify(args, false, null, System.err), 0);
    assertTrue(DirectoryServer.getSchema().hasAttributeType(attrName));
  }
  /**
   * Tests the behavior of the schema backend when attempting to replace an
   * attribute type definition in a custom schema file.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  public void testReplaceAttributeTypeInAltSchemaFile()
         throws Exception
  {
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "add: attributeTypes",
         "attributeTypes: ( testreplaceattributetypeinaltschemafile-oid " +
              "NAME 'testReplaceAttributeTypeInAltSchemaFile' " +
              "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE " +
              "X-ORIGIN 'SchemaBackendTestCase' " +
              "X-SCHEMA-FILE '98-schema-test-replaceattrtype.ldif' )",
         "",
         "dn: cn=schema",
         "changetype: modify",
         "add: attributeTypes",
         "attributeTypes: ( testreplaceattributetypeinaltschemafile-oid " +
              "NAME 'testReplaceAttributeTypeInAltSchemaFile' " +
              "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE " +
              "X-ORIGIN 'SchemaBackendTestCase' )");
    String attrName = "testreplaceattributetypeinaltschemafile";
    assertFalse(DirectoryServer.getSchema().hasAttributeType(attrName));
    File schemaFile = new File(SchemaConfigManager.getSchemaDirectoryPath(),
                               "98-schema-test-replaceattrtype.ldif");
    assertFalse(schemaFile.exists());
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    assertEquals(LDAPModify.mainModify(args, false, null, System.err), 0);
    assertTrue(DirectoryServer.getSchema().hasAttributeType(attrName));
    assertTrue(schemaFile.exists());
  }
  /**
   * Tests the behavior of the schema backend when attempting to add a new
   * attribute type definition that can't be parsed.
   *
   * @throws  Exception  If an unexpected problem occurs.
@@ -548,6 +835,456 @@
  /**
   * Tests the behavior of the schema backend when attempting to add a new
   * attribute type that conflicts with multiple existing types.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testAddAttributeTypeMultipleConflicts()
         throws Exception
  {
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "add: attributeTypes",
         "attributeTypes: ( testaddattributetypemultipleconflicts-oid NAME " +
              "( 'testAddAttributeTypeMultipleConflicts' 'cn' 'uid' ) SYNTAX " +
              "1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN " +
              "'SchemaBackendTestCase' )");
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    assertFalse(LDAPModify.mainModify(args, false, null, null) == 0);
  }
  /**
   * Tests the behavior of the schema backend when attempting to add a new
   * attribute type that references an undefined superior attribute type.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testAddAttributeTypeUndefinedSuperior()
         throws Exception
  {
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "add: attributeTypes",
         "attributeTypes: ( testaddattributetypeundefinedsuperior-oid NAME " +
              "'testAddAttributeTypeUndefinedSuperior' SUP undefined SYNTAX " +
              "1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN " +
              "'SchemaBackendTestCase' )");
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    assertFalse(LDAPModify.mainModify(args, false, null, null) == 0);
  }
  /**
   * Tests the behavior of the schema backend when attempting to remove an
   * attribute type that is defined in the server schema and does not have any
   * dependencies.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testRemoveAttributeTypeSuccessful()
         throws Exception
  {
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "add: attributeTypes",
         "attributeTypes: ( 1.3.6.1.4.1.26027.1.999.6 NAME " +
              "'testRemoveAttributeTypeSuccessful' SYNTAX " +
              "1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN " +
              "'SchemaBackendTestCase' )",
         "",
         "dn: cn=schema",
         "changetype: modify",
         "delete: attributeTypes",
         "attributeTypes: ( 1.3.6.1.4.1.26027.1.999.6 NAME " +
              "'testRemoveAttributeTypeSuccessful' SYNTAX " +
              "1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN " +
              "'SchemaBackendTestCase' )");
    String attrName = "testremoveattributetypesuccessful";
    assertFalse(DirectoryServer.getSchema().hasAttributeType(attrName));
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    assertEquals(LDAPModify.mainModify(args, false, null, System.err), 0);
    assertFalse(DirectoryServer.getSchema().hasAttributeType(attrName));
  }
  /**
   * Tests the behavior of the schema backend when attempting to remove an
   * attribute type and add it back in the same modification.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testRemoveThenAddAttributeTypeSuccessful()
         throws Exception
  {
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "add: attributeTypes",
         "attributeTypes: ( testremovethenaddattributetypesuccessful-oid " +
              "NAME 'testRemoveThenAddAttributeTypeSuccessful' " +
              "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE " +
              "X-ORIGIN 'SchemaBackendTestCase' )",
         "",
         "dn: cn=schema",
         "changetype: modify",
         "delete: attributeTypes",
         "attributeTypes: ( testremovethenaddattributetypesuccessful-oid " +
              "NAME 'testRemoveThenAddAttributeTypeSuccessful' " +
              "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE " +
              "X-ORIGIN 'SchemaBackendTestCase' )",
         "-",
         "add: attributeTypes",
         "attributeTypes: ( testremovethenaddattributetypesuccessful-oid " +
              "NAME 'testRemoveThenAddAttributeTypeSuccessful' " +
              "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE " +
              "X-ORIGIN 'SchemaBackendTestCase' )");
    String attrName = "testremoveattributetypesuccessful";
    assertFalse(DirectoryServer.getSchema().hasAttributeType(attrName));
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    assertEquals(LDAPModify.mainModify(args, false, null, System.err), 0);
    assertFalse(DirectoryServer.getSchema().hasAttributeType(attrName));
  }
  /**
   * Tests the behavior of the schema backend when attempting to remove an
   * attribute type that is not defined in the server schema.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testRemoveAttributeTypeUndefined()
         throws Exception
  {
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "delete: attributeTypes",
         "attributeTypes: ( testremoveattributetypeundefined-oid " +
              "NAME 'testRemoveAttributeTypeUndefined' " +
              "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE " +
              "X-ORIGIN 'SchemaBackendTestCase' )");
    String attrName = "testremoveattributetypeundefined";
    assertFalse(DirectoryServer.getSchema().hasAttributeType(attrName));
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    assertFalse(LDAPModify.mainModify(args, false, null, null) == 0);
  }
  /**
   * Tests the behavior of the schema backend when attempting to remove an
   * attribute type that is referenced as the superior type for another
   * attribute type.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testRemoveSuperiorAttributeType()
         throws Exception
  {
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "delete: attributeTypes",
         "attributeTypes: ( 2.5.4.41 NAME 'name' EQUALITY caseIgnoreMatch " +
              "SUBSTR caseIgnoreSubstringsMatch " +
              "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{32768} " +
              "X-ORIGIN 'RFC 2256' )");
    String attrName = "name";
    assertTrue(DirectoryServer.getSchema().hasAttributeType(attrName));
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    assertFalse(LDAPModify.mainModify(args, false, null, null) == 0);
    assertTrue(DirectoryServer.getSchema().hasAttributeType(attrName));
  }
  /**
   * Tests the behavior of the schema backend when attempting to remove an
   * attribute type that is referenced by an existing objectclass.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testRemoveAttributeTypeReferencedByObjectClass()
         throws Exception
  {
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "delete: attributeTypes",
         "attributeTypes: ( 0.9.2342.19200300.100.1.1 NAME 'uid' " +
              "EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch " +
              "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} " +
              "X-ORIGIN 'RFC 1274' )");
    String attrName = "uid";
    assertTrue(DirectoryServer.getSchema().hasAttributeType(attrName));
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    assertFalse(LDAPModify.mainModify(args, false, null, null) == 0);
    assertTrue(DirectoryServer.getSchema().hasAttributeType(attrName));
  }
  /**
   * Tests the behavior of the schema backend when attempting to remove an
   * attribute type that is referenced by an existing name form.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testRemoveAttributeTypeReferencedByNameForm()
         throws Exception
  {
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "add: attributeTypes",
         "attributeTypes: ( testremoveattributetypereferencedbynf-oid " +
              "NAME 'testRemoveAttributeTypeReferencedByNF' " +
              "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE " +
              "X-ORIGIN 'SchemaBackendTestCase' )",
         "-",
         "add: objectClasses",
         "objectClasses:  ( testremoveattributetypereferencedbynfoc-oid " +
              "NAME 'testRemoveAttributeTypeReferencedByNFOC' SUP top " +
              "STRUCTURAL MUST cn X-ORIGIN 'SchemaBackendTestCase')",
         "-",
         "add: nameForms",
         "nameForms: ( testremoveattributetypereferencedbynfnf-oid " +
              "NAME 'testRemoveAttributeTypeReferencedByNFNF' " +
              "OC testRemoveAttributeTypeReferencedByNFOC " +
              "MUST testRemoveAttributeTypeReferencedByNF " +
              "X-ORIGIN 'SchemaBackendTestCase' )",
         "",
         "dn: cn=schema",
         "changetype: modify",
         "delete: attributeTypes",
         "attributeTypes: ( testremoveattributetypereferencedbynf-oid " +
              "NAME 'testRemoveAttributeTypeReferencedByNF' " +
              "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE " +
              "X-ORIGIN 'SchemaBackendTestCase' )");
    String attrName = "testremoveattributetypereferencedbynf";
    assertFalse(DirectoryServer.getSchema().hasAttributeType(attrName));
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    assertFalse(LDAPModify.mainModify(args, false, null, null) == 0);
    assertTrue(DirectoryServer.getSchema().hasAttributeType(attrName));
  }
  /**
   * Tests the behavior of the schema backend when attempting to remove an
   * attribute type that is referenced by an existing DIT content rule.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testRemoveAttributeTypeReferencedByDCR()
         throws Exception
  {
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "add: attributeTypes",
         "attributeTypes: ( testremoveattributetypereferencedbydcr-oid " +
              "NAME 'testRemoveAttributeTypeReferencedByDCR' " +
              "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE " +
              "X-ORIGIN 'SchemaBackendTestCase' )",
         "-",
         "add: objectClasses",
         "objectClasses:  ( testremoveattributetypereferencedbydcroc-oid " +
              "NAME 'testRemoveAttributeTypeReferencedByDCROC' SUP top " +
              "STRUCTURAL MUST cn X-ORIGIN 'SchemaBackendTestCase')",
         "-",
         "add: ditContentRules",
         "ditContentRules: ( testremoveattributetypereferencedbydcroc-oid " +
              "NAME 'testRemoveAttributeTypeReferencedByDCRDCR' " +
              "MAY testRemoveAttributeTypeReferencedByDCR " +
              "X-ORIGIN 'SchemaBackendTestCase' )",
         "",
         "dn: cn=schema",
         "changetype: modify",
         "delete: attributeTypes",
         "attributeTypes: ( testremoveattributetypereferencedbydcr-oid " +
              "NAME 'testRemoveAttributeTypeReferencedByDCR' " +
              "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE " +
              "X-ORIGIN 'SchemaBackendTestCase' )");
    String attrName = "testremoveattributetypereferencedbydcr";
    assertFalse(DirectoryServer.getSchema().hasAttributeType(attrName));
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    assertFalse(LDAPModify.mainModify(args, false, null, null) == 0);
    assertTrue(DirectoryServer.getSchema().hasAttributeType(attrName));
  }
  /**
   * Tests the behavior of the schema backend when attempting to remove an
   * attribute type that is referenced by an existing matching rule use.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testRemoveAttributeTypeReferencedByMRU()
         throws Exception
  {
    SchemaTestMatchingRule matchingRule =
         new SchemaTestMatchingRule("testRemoveATRefByMRUMatch",
                                    "1.3.6.1.4.1.26027.1.999.17");
    DirectoryServer.registerMatchingRule(matchingRule, false);
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "add: attributeTypes",
         "attributeTypes: ( testremoveatrefbymruat-oid " +
              "NAME 'testRemoveATRefByMRUAT' " +
              "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE " +
              "X-ORIGIN 'SchemaBackendTestCase' )",
         "-",
         "add: matchingRuleUse",
         "matchingRuleUse: ( 1.3.6.1.4.1.26027.1.999.17 " +
              "NAME 'testRemoveATRefByMRUMRU' APPLIES testRemoveATRefByMRUAT " +
              "X-ORIGIN 'SchemaBackendTestCase' )",
         "",
         "dn: cn=schema",
         "changetype: modify",
         "delete: attributeTypes",
         "attributeTypes: ( testremoveatrefbymruat-oid " +
              "NAME 'testRemoveATRefByMRUAT' " +
              "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE " +
              "X-ORIGIN 'SchemaBackendTestCase' )");
    String attrName = "testremoveatrefbymruat";
    assertFalse(DirectoryServer.getSchema().hasAttributeType(attrName));
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    assertFalse(LDAPModify.mainModify(args, false, null, null) == 0);
    MatchingRuleUse mru =
         DirectoryServer.getSchema().getMatchingRuleUse(matchingRule);
    assertNotNull(mru);
    assertTrue(mru.hasName("testremoveatrefbymrumru"));
    assertTrue(DirectoryServer.getSchema().hasAttributeType(attrName));
  }
  /**
   * Tests the behavior of the schema backend when attempting to add a new
   * objectclass that doesn't already exist, that has a valid superior class,
   * and for which all attributes contained in it are already defined.
   *
@@ -623,6 +1360,178 @@
  /**
   * Tests the behavior of the schema backend when attempting to add a new
   * objectclass to a specific schema file.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testAddObjectClassToAltSchemaFile()
         throws Exception
  {
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "add: objectClasses",
         "objectClasses: ( testaddobjectclasstoaltschemafile-oid NAME " +
              "'testAddObjectClassToAltSchemaFile' SUP top STRUCTURAL " +
              "MUST cn X-ORIGIN 'SchemaBackendTestCase' " +
              "X-SCHEMA-FILE '98-schema-test-oc.ldif' )");
    String ocName = "testaddobjectclasstoaltschemafile";
    assertFalse(DirectoryServer.getSchema().hasObjectClass(ocName));
    File schemaFile = new File(SchemaConfigManager.getSchemaDirectoryPath(),
                               "98-schema-test-oc.ldif");
    assertFalse(schemaFile.exists());
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    assertEquals(LDAPModify.mainModify(args, false, null, System.err), 0);
    assertTrue(DirectoryServer.getSchema().hasObjectClass(ocName));
    assertTrue(schemaFile.exists());
  }
  /**
   * Tests the behavior of the schema backend when attempting to add a new
   * objectclass that already exists (i.e., a replace)
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testAddObjectClassSuccessfulReplace()
         throws Exception
  {
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "add: objectClasses",
         "objectClasses: ( testaddobjectclasssuccessfulreplace-oid " +
              "NAME 'testAddObjectClassSuccessfulReplace' SUP top STRUCTURAL " +
              "MUST cn X-ORIGIN 'SchemaBackendTestCase' )",
         "",
         "dn: cn=schema",
         "changetype: modify",
         "add: objectClasses",
         "objectClasses: ( testaddobjectclasssuccessfulreplace-oid " +
              "NAME 'testAddObjectClassSuccessfulReplace' SUP top STRUCTURAL " +
              "MUST cn MAY description X-ORIGIN 'SchemaBackendTestCase' )");
    String ocName = "testaddobjectclasssuccessfulreplace";
    assertFalse(DirectoryServer.getSchema().hasObjectClass(ocName));
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    assertEquals(LDAPModify.mainModify(args, false, null, System.err), 0);
    assertTrue(DirectoryServer.getSchema().hasObjectClass(ocName));
  }
  /**
   * Tests the behavior of the schema backend when attempting to add a new
   * objectclass that conflicts with multiple existing objectclasses.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testAddObjectClassMultipleConflicts()
         throws Exception
  {
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "add: objectClasses",
         "objectClasses: ( testaddobjectclassmultipleconflicts-oid " +
              "NAME ( 'testAddObjectClassMultipleConflicts' 'person' " +
              "'device' ) SUP top STRUCTURAL MUST cn " +
              "X-ORIGIN 'SchemaBackendTestCase' )");
    String ocName = "testaddobjectclassmultipleconflicts";
    assertFalse(DirectoryServer.getSchema().hasObjectClass(ocName));
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    assertFalse(LDAPModify.mainModify(args, false, null, null) == 0);
    assertFalse(DirectoryServer.getSchema().hasObjectClass(ocName));
  }
  /**
   * Tests the behavior of the schema backend when attempting to remove an
   * existing objectclass definition and then add it back in the same operation
   * with a different definition.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testRemoveThenAddAddObjectClassSuccessful()
         throws Exception
  {
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "add: objectClasses",
         "objectClasses: ( testremovethenaddobjectclasssuccessful-oid " +
              "NAME 'testRemoveThenAddObjectClassSuccessful' SUP top " +
              "STRUCTURAL MUST cn X-ORIGIN 'SchemaBackendTestCase' )",
         "",
         "dn: cn=schema",
         "changetype: modify",
         "delete: objectClasses",
         "objectClasses: ( testremovethenaddobjectclasssuccessful-oid " +
              "NAME 'testRemoveThenAddObjectClassSuccessful' SUP top " +
              "STRUCTURAL MUST cn X-ORIGIN 'SchemaBackendTestCase' )",
         "-",
         "add: objectClasses",
         "objectClasses: ( testremovethenaddobjectclasssuccessful-oid " +
              "NAME 'testRemoveThenAddObjectClassSuccessful' SUP top " +
              "STRUCTURAL MUST cn MAY description " +
              "X-ORIGIN 'SchemaBackendTestCase' )");
    String ocName = "testremovethenaddobjectclasssuccessful";
    assertFalse(DirectoryServer.getSchema().hasObjectClass(ocName));
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    assertEquals(LDAPModify.mainModify(args, false, null, System.err), 0);
    assertTrue(DirectoryServer.getSchema().hasObjectClass(ocName));
  }
  /**
   * Tests the behavior of the schema backend when attempting to add a new
   * objectclass definition that can't be parsed.
   *
   * @throws  Exception  If an unexpected problem occurs.
@@ -744,5 +1653,2119 @@
    assertFalse(LDAPModify.mainModify(args, false, null, null) == 0);
  }
  /**
   * Tests the behavior of the schema backend when attempting to remove an
   * objectclass that exists and for which there are no dependencies.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testRemoveObjectClassSuccessful()
         throws Exception
  {
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "add: objectClasses",
         "objectClasses: ( 1.3.6.1.4.1.26027.1.999.7 NAME " +
              "'testRemoveObjectClassSuccessful' SUP top STRUCTURAL MUST cn " +
              "X-ORIGIN 'SchemaBackendTestCase' )",
         "",
         "dn: cn=schema",
         "changetype: modify",
         "delete: objectClasses",
         "objectClasses: ( 1.3.6.1.4.1.26027.1.999.7 NAME " +
              "'testRemoveObjectClassSuccessful' SUP top STRUCTURAL MUST cn " +
              "X-ORIGIN 'SchemaBackendTestCase' )");
    String ocName = "testremoveobjectclasssuccessful";
    assertFalse(DirectoryServer.getSchema().hasObjectClass(ocName));
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    assertEquals(LDAPModify.mainModify(args, false, null, System.err), 0);
    assertFalse(DirectoryServer.getSchema().hasObjectClass(ocName));
  }
  /**
   * Tests the behavior of the schema backend when attempting to remove an
   * objectclass that is the superior class for another objectclass.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testRemoveSuperiorObjectClass()
         throws Exception
  {
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "delete: objectClasses",
         "objectClasses: ( 2.5.6.6 NAME 'person' SUP top STRUCTURAL " +
              "MUST ( sn $ cn ) MAY ( userPassword $ telephoneNumber $ " +
              "seeAlso $ description ) X-ORIGIN 'RFC 2256' )");
    String ocName = "person";
    assertTrue(DirectoryServer.getSchema().hasObjectClass(ocName));
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    assertFalse(LDAPModify.mainModify(args, false, null, null) == 0);
    assertTrue(DirectoryServer.getSchema().hasObjectClass(ocName));
  }
  /**
   * Tests the behavior of the schema backend when attempting to remove an
   * objectclass that is referenced by an existing name form.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testRemoveObjectClassReferencedByNameForm()
         throws Exception
  {
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "add: objectClasses",
         "objectClasses:  ( testremoveobjectclassreferencedbynf-oid " +
              "NAME 'testRemoveObjectClassReferencedByNF' SUP top " +
              "STRUCTURAL MUST cn X-ORIGIN 'SchemaBackendTestCase')",
         "-",
         "add: nameForms",
         "nameForms: ( testremoveattributetypereferencedbynfnf-oid " +
              "NAME 'testRemoveObjectClassReferencedByNFNF' " +
              "OC testRemoveObjectClassReferencedByNF MUST cn " +
              "X-ORIGIN 'SchemaBackendTestCase' )",
         "",
         "dn: cn=schema",
         "changetype: modify",
         "delete: objectClasses",
         "objectClasses:  ( testremoveobjectclassreferencedbynf-oid " +
              "NAME 'testRemoveObjectClassReferencedByNF' SUP top " +
              "STRUCTURAL MUST cn X-ORIGIN 'SchemaBackendTestCase')");
    String ocName = "testremoveobjectclassreferencedbynf";
    assertFalse(DirectoryServer.getSchema().hasObjectClass(ocName));
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    assertFalse(LDAPModify.mainModify(args, false, null, null) == 0);
    assertTrue(DirectoryServer.getSchema().hasObjectClass(ocName));
  }
  /**
   * Tests the behavior of the schema backend when attempting to remove an
   * objectclass that is referenced by an existing DIT content rule.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testRemoveObjectClassReferencedByDCR()
         throws Exception
  {
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "add: objectClasses",
         "objectClasses:  ( testremoveobjectclassreferencedbydcr-oid " +
              "NAME 'testRemoveObjectClassReferencedByDCR' SUP top " +
              "STRUCTURAL MUST cn X-ORIGIN 'SchemaBackendTestCase')",
         "-",
         "add: ditContentRules",
         "ditContentRules: ( testremoveobjectclassreferencedbydcr-oid " +
              "NAME 'testRemoveObjectClassReferencedByDCRDCR' " +
              "MAY description X-ORIGIN 'SchemaBackendTestCase' )",
         "",
         "dn: cn=schema",
         "changetype: modify",
         "delete: objectClasses",
         "objectClasses:  ( testremoveobjectclassreferencedbydcr-oid " +
              "NAME 'testRemoveObjectClassReferencedByDCR' SUP top " +
              "STRUCTURAL MUST cn X-ORIGIN 'SchemaBackendTestCase')");
    String ocName = "testremoveobjectclassreferencedbydcr";
    assertFalse(DirectoryServer.getSchema().hasObjectClass(ocName));
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    assertFalse(LDAPModify.mainModify(args, false, null, null) == 0);
    assertTrue(DirectoryServer.getSchema().hasObjectClass(ocName));
  }
  /**
   * Tests the behavior of the schema backend when attempting to add a new name
   * form that doesn't already exist.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testAddNameFormSuccessful()
         throws Exception
  {
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "add: objectClasses",
         "objectClasses:  ( testaddnameformsuccessfuloc-oid " +
              "NAME 'testAddNameFormSuccessfulOC' SUP top STRUCTURAL MUST cn " +
              "X-ORIGIN 'SchemaBackendTestCase')",
         "-",
         "add: nameForms",
         "nameForms: ( 1.3.6.1.4.1.26027.1.999.8 " +
              "NAME 'testAddNameFormSuccessful' " +
              "OC testAddNameFormSuccessfulOC MUST cn " +
              "X-ORIGIN 'SchemaBackendTestCase' )");
    String nameFormName = "testaddnameformsuccessful";
    assertFalse(DirectoryServer.getSchema().hasNameForm(nameFormName));
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    assertEquals(LDAPModify.mainModify(args, false, null, System.err), 0);
    assertTrue(DirectoryServer.getSchema().hasNameForm(nameFormName));
  }
  /**
   * Tests the behavior of the schema backend when attempting to add a new name
   * form that doesn't already exist to an alternate schema file.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testAddNameFormToAltSchemaFile()
         throws Exception
  {
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "add: objectClasses",
         "objectClasses:  ( testaddnameformtoaltschemafileoc-oid " +
              "NAME 'testAddNameFormToAltSchemaFileOC' SUP top STRUCTURAL " +
              "MUST cn X-ORIGIN 'SchemaBackendTestCase')",
         "-",
         "add: nameForms",
         "nameForms: ( testaddnameformtoaltschemafile-oid " +
              "NAME 'testAddNameFormToAltSchemaFile' " +
              "OC testAddNameFormToAltSchemaFileOC MUST cn " +
              "X-ORIGIN 'SchemaBackendTestCase' " +
              "X-SCHEMA-FILE '98-schema-test-nameform.ldif' )");
    String nameFormName = "testaddnameformtoaltschemafile";
    assertFalse(DirectoryServer.getSchema().hasNameForm(nameFormName));
    File schemaFile = new File(SchemaConfigManager.getSchemaDirectoryPath(),
                               "98-schema-test-nameform.ldif");
    assertFalse(schemaFile.exists());
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    assertEquals(LDAPModify.mainModify(args, false, null, System.err), 0);
    assertTrue(DirectoryServer.getSchema().hasNameForm(nameFormName));
    assertTrue(schemaFile.exists());
  }
  /**
   * Tests the behavior of the schema backend when attempting to add a new name
   * form that references a required attribute type not defined in the server
   * schema.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testAddNameFormWithUndefinedReqAT()
         throws Exception
  {
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "add: objectClasses",
         "objectClasses:  ( testaddnameformwithundefinedreqatoc-oid " +
              "NAME 'testAddNameFormWithUndefinedReqATOC' SUP top STRUCTURAL " +
              "MUST cn X-ORIGIN 'SchemaBackendTestCase')",
         "-",
         "add: nameForms",
         "nameForms: ( testaddnameformwithundefinereqdat-oid " +
              "NAME 'testAddNameFormWithUndefinedReqAT' " +
              "OC testAddNameFormWithUndefinedReqATOC MUST xxxundefinedxxx " +
              "X-ORIGIN 'SchemaBackendTestCase' )");
    String nameFormName = "testaddnameformwithundefinedreqat";
    assertFalse(DirectoryServer.getSchema().hasNameForm(nameFormName));
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    assertFalse(LDAPModify.mainModify(args, false, null, null) == 0);
    assertFalse(DirectoryServer.getSchema().hasNameForm(nameFormName));
  }
  /**
   * Tests the behavior of the schema backend when attempting to add a new name
   * form that references an optional attribute type not defined in the server
   * schema.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testAddNameFormWithUndefinedOptAT()
         throws Exception
  {
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "add: objectClasses",
         "objectClasses:  ( testaddnameformwithundefinedoptatoc-oid " +
              "NAME 'testAddNameFormWithUndefinedOptATOC' SUP top STRUCTURAL " +
              "MUST cn X-ORIGIN 'SchemaBackendTestCase')",
         "-",
         "add: nameForms",
         "nameForms: ( testaddnameformwithundefineoptdat-oid " +
              "NAME 'testAddNameFormWithUndefinedOptAT' " +
              "OC testAddNameFormWithUndefinedOptATOC MUST cn " +
              "MAY xxxundefinedxxx X-ORIGIN 'SchemaBackendTestCase' )");
    String nameFormName = "testaddnameformwithundefinedoptat";
    assertFalse(DirectoryServer.getSchema().hasNameForm(nameFormName));
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    assertFalse(LDAPModify.mainModify(args, false, null, null) == 0);
    assertFalse(DirectoryServer.getSchema().hasNameForm(nameFormName));
  }
  /**
   * Tests the behavior of the schema backend when attempting to add a new name
   * form whose structural objectclass is not defined in the server schema.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testAddNameFormWithUndefinedOC()
         throws Exception
  {
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "add: nameForms",
         "nameForms: ( testaddnameformwithundefinedoc-oid " +
              "NAME 'testAddNameFormWithUndefinedOC' " +
              "OC xxxundefinedxxx MUST cn X-ORIGIN 'SchemaBackendTestCase' )");
    String nameFormName = "testaddnameformwithundefinedoc";
    assertFalse(DirectoryServer.getSchema().hasNameForm(nameFormName));
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    assertFalse(LDAPModify.mainModify(args, false, null, null) == 0);
    assertFalse(DirectoryServer.getSchema().hasNameForm(nameFormName));
  }
  /**
   * Tests the behavior of the schema backend when attempting to add a new name
   * form whose objectclass auxiliary rather than structural.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testAddNameFormWithAuxiliaryOC()
         throws Exception
  {
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "add: objectClasses",
         "objectClasses:  ( testaddnameformwithauxiliaryococ-oid " +
              "NAME 'testAddNameFormWithAuxiliaryOCOC' SUP top AUXILIARY " +
              "MUST cn X-ORIGIN 'SchemaBackendTestCase')",
         "-",
         "add: nameForms",
         "nameForms: ( testaddnameformwithauxiliaryoc-oid " +
              "NAME 'testAddNameFormWithAuxiliaryOC' " +
              "OC testAddNameFormWithAuxiliaryOCOC MUST cn " +
              "X-ORIGIN 'SchemaBackendTestCase' )");
    String nameFormName = "testaddnameformwithauxiliaryoc";
    assertFalse(DirectoryServer.getSchema().hasNameForm(nameFormName));
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    assertFalse(LDAPModify.mainModify(args, false, null, null) == 0);
    assertFalse(DirectoryServer.getSchema().hasNameForm(nameFormName));
  }
  /**
   * Tests the behavior of the schema backend when attempting to add a new name
   * form that references a structural objectclass already referenced by another
   * name form.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testAddNameFormOCConflict()
         throws Exception
  {
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "add: objectClasses",
         "objectClasses:  ( testaddnameformocconflictoc-oid " +
              "NAME 'testAddNameFormOCConflictOC' SUP top STRUCTURAL MUST cn " +
              "X-ORIGIN 'SchemaBackendTestCase')",
         "-",
         "add: nameForms",
         "nameForms: ( testaddnameformocconflict-oid " +
              "NAME 'testAddNameFormOCConflict' " +
              "OC testAddNameFormOCConflictOC MUST cn " +
              "X-ORIGIN 'SchemaBackendTestCase' )",
         "",
         "dn: cn=schema",
         "changetype: modify",
         "add: nameForms",
         "nameForms: ( testaddnameformocconflict2-oid " +
              "NAME 'testAddNameFormOCConflict2' " +
              "OC testAddNameFormOCConflictOC MUST cn " +
              "X-ORIGIN 'SchemaBackendTestCase' )");
    String nameFormName = "testaddnameformocconflict2";
    assertFalse(DirectoryServer.getSchema().hasNameForm(nameFormName));
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    assertFalse(LDAPModify.mainModify(args, false, null, null) == 0);
    assertFalse(DirectoryServer.getSchema().hasNameForm(nameFormName));
  }
  /**
   * Tests the behavior of the schema backend when attempting to remove an
   * existing name form.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testRemoveNameFormSuccessful()
         throws Exception
  {
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "add: objectClasses",
         "objectClasses:  ( testremovenameformsuccessfuloc-oid " +
              "NAME 'testRemoveNameFormSuccessfulOC' SUP top STRUCTURAL " +
              "MUST cn X-ORIGIN 'SchemaBackendTestCase')",
         "-",
         "add: nameForms",
         "nameForms: ( 1.3.6.1.4.1.26027.1.999.9 " +
              "NAME 'testRemoveNameFormSuccessful' " +
              "OC testRemoveNameFormSuccessfulOC MUST cn " +
              "X-ORIGIN 'SchemaBackendTestCase' )",
         "",
         "dn: cn=schema",
         "changetype: modify",
         "delete: nameForms",
         "nameForms: ( 1.3.6.1.4.1.26027.1.999.9 " +
              "NAME 'testRemoveNameFormSuccessful' " +
              "OC testRemoveNameFormSuccessfulOC MUST cn " +
              "X-ORIGIN 'SchemaBackendTestCase' )");
    String nameFormName = "testremovenameformsuccessful";
    assertFalse(DirectoryServer.getSchema().hasNameForm(nameFormName));
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    assertEquals(LDAPModify.mainModify(args, false, null, System.err), 0);
    assertFalse(DirectoryServer.getSchema().hasNameForm(nameFormName));
  }
  /**
   * Tests the behavior of the schema backend when attempting to remove an
   * existing name form and then add it back in the same operation.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testRemoveThenAddNameFormSuccessful()
         throws Exception
  {
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "add: objectClasses",
         "objectClasses:  ( testremovethenaddnameformsuccessfuloc-oid " +
              "NAME 'testRemoveThenAddNameFormSuccessfulOC' SUP top " +
              "STRUCTURAL MUST cn X-ORIGIN 'SchemaBackendTestCase' )",
         "-",
         "add: nameForms",
         "nameForms: ( testremovethenaddnameformsuccessful-oid " +
              "NAME 'testRemoveThenAddNameFormSuccessful' " +
              "OC testRemoveThenAddNameFormSuccessfulOC MUST cn " +
              "X-ORIGIN 'SchemaBackendTestCase' )",
         "",
         "dn: cn=schema",
         "changetype: modify",
         "delete: nameForms",
         "nameForms: ( testremovethenaddnameformsuccessful-oid " +
              "NAME 'testRemoveThenAddNameFormSuccessful' " +
              "OC testRemoveThenAddNameFormSuccessfulOC MUST cn " +
              "X-ORIGIN 'SchemaBackendTestCase' )",
         "-",
         "add: nameForms",
         "nameForms: ( testremovethenaddnameformsuccessful-oid " +
              "NAME 'testRemoveThenAddNameFormSuccessful' " +
              "OC testRemoveThenAddNameFormSuccessfulOC MUST cn MAY sn " +
              "X-ORIGIN 'SchemaBackendTestCase' )");
    String nameFormName = "testremovethenaddnameformsuccessful";
    assertFalse(DirectoryServer.getSchema().hasNameForm(nameFormName));
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    assertEquals(LDAPModify.mainModify(args, false, null, System.err), 0);
    assertTrue(DirectoryServer.getSchema().hasNameForm(nameFormName));
  }
  /**
   * Tests the behavior of the schema backend when attempting to remove a name
   * form that is referenced by a DIT structure rule.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testRemoveNameFormReferencedByDSR()
         throws Exception
  {
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "add: objectClasses",
         "objectClasses:  ( testremovenameformreferencedbydsroc-oid " +
              "NAME 'testRemoveNameFormReferencedByDSROC' SUP top " +
              "STRUCTURAL MUST cn X-ORIGIN 'SchemaBackendTestCase')",
         "-",
         "add: nameForms",
         "nameForms: ( testremovenameformreferencedbydsrnf-oid " +
              "NAME 'testRemoveNameFormReferencedByDSRNF' " +
              "OC testRemoveNameFormReferencedByDSROC MUST cn " +
              "X-ORIGIN 'SchemaBackendTestCase' )",
         "-",
         "add: ditStructureRules",
         "ditStructureRules: ( 999009 " +
              "NAME 'testRemoveNameFormReferencedByDSRDSR' " +
              "FORM testRemoveNameFormReferencedByDSRNF " +
              "X-ORIGIN 'SchemaBackendTestCase' )",
         "",
         "dn: cn=schema",
         "changetype: modify",
         "delete: nameForms",
         "nameForms: ( testremovenameformreferencedbydsrnf-oid " +
              "NAME 'testRemoveNameFormReferencedByDSRNF' " +
              "OC testRemoveNameFormReferencedByDSROC MUST cn " +
              "X-ORIGIN 'SchemaBackendTestCase' )");
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    String nameFormName = "testremovenameformreferencedbydsrnf";
    assertFalse(DirectoryServer.getSchema().hasNameForm(nameFormName));
    assertFalse(LDAPModify.mainModify(args, false, null, null) == 0);
    assertTrue(DirectoryServer.getSchema().hasNameForm(nameFormName));
  }
  /**
   * Tests the behavior of the schema backend when attempting to add a new DIT
   * content rule that doesn't already exist.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testAddDITContentRuleSuccessful()
         throws Exception
  {
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "add: objectClasses",
         "objectClasses:  ( testaddditcontentrulesuccessfuloc-oid " +
              "NAME 'testAddDITContentRuleSuccessfulOC' SUP top STRUCTURAL " +
              "MUST cn X-ORIGIN 'SchemaBackendTestCase')",
         "-",
         "add: ditContentRules",
         "ditContentRules: ( testaddditcontentrulesuccessfuloc-oid " +
              "NAME 'testAddDITContentRuleSuccessful' NOT description " +
              "X-ORIGIN 'SchemaBackendTestCase' )");
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    String ocName = "testaddditcontentrulesuccessfuloc";
    assertFalse(DirectoryServer.getSchema().hasObjectClass(ocName));
    assertEquals(LDAPModify.mainModify(args, false, null, System.err), 0);
    ObjectClass oc = DirectoryServer.getSchema().getObjectClass(ocName);
    assertNotNull(oc);
    DITContentRule dcr = DirectoryServer.getSchema().getDITContentRule(oc);
    assertNotNull(dcr);
    assertTrue(dcr.hasName("testaddditcontentrulesuccessful"));
  }
  /**
   * Tests the behavior of the schema backend when attempting to replace an
   * existing DIT content rule.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testReplaceDITContentRuleSuccessful()
         throws Exception
  {
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "add: objectClasses",
         "objectClasses:  ( testreplaceditcontentrulesuccessfuloc-oid " +
              "NAME 'testReplaceDITContentRuleSuccessfulOC' SUP top " +
              "STRUCTURAL MUST cn X-ORIGIN 'SchemaBackendTestCase')",
         "-",
         "add: ditContentRules",
         "ditContentRules: ( testreplaceditcontentrulesuccessfuloc-oid " +
              "NAME 'testReplaceDITContentRuleSuccessful' NOT description " +
              "X-ORIGIN 'SchemaBackendTestCase' )",
         "",
         "dn: cn=schema",
         "changetype: modify",
         "add: ditContentRules",
         "ditContentRules: ( testreplaceditcontentrulesuccessfuloc-oid " +
              "NAME 'testReplaceDITContentRuleSuccessful' MAY sn " +
              "NOT description X-ORIGIN 'SchemaBackendTestCase' )");
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    String ocName = "testreplaceditcontentrulesuccessfuloc";
    assertFalse(DirectoryServer.getSchema().hasObjectClass(ocName));
    assertEquals(LDAPModify.mainModify(args, false, null, System.err), 0);
    ObjectClass oc = DirectoryServer.getSchema().getObjectClass(ocName);
    assertNotNull(oc);
    DITContentRule dcr = DirectoryServer.getSchema().getDITContentRule(oc);
    assertNotNull(dcr);
    assertTrue(dcr.hasName("testreplaceditcontentrulesuccessful"));
  }
  /**
   * Tests the behavior of the schema backend when attempting to add a new DIT
   * content rule to an alternate schema file.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testAddDITContentRuleToAltSchemaFile()
         throws Exception
  {
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "add: objectClasses",
         "objectClasses:  ( testadddcrtoaltschemafileoc-oid " +
              "NAME 'testAddDCRToAltSchemaFileOC' SUP top STRUCTURAL " +
              "MUST cn X-SCHEMA-FILE '98-schema-test-dcr.ldif' " +
              "X-ORIGIN 'SchemaBackendTestCase')",
         "-",
         "add: ditContentRules",
         "ditContentRules: ( testadddcrtoaltschemafileoc-oid " +
              "NAME 'testAddDCRToAltSchemaFile' NOT description " +
              "X-SCHEMA-FILE '98-schema-test-dcr.ldif' " +
              "X-ORIGIN 'SchemaBackendTestCase' )");
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    String ocName = "testadddcrtoaltschemafileoc";
    assertFalse(DirectoryServer.getSchema().hasObjectClass(ocName));
    File schemaFile = new File(SchemaConfigManager.getSchemaDirectoryPath(),
                               "98-schema-test-dcr.ldif");
    assertFalse(schemaFile.exists());
    assertEquals(LDAPModify.mainModify(args, false, null, System.err), 0);
    ObjectClass oc = DirectoryServer.getSchema().getObjectClass(ocName);
    assertNotNull(oc);
    DITContentRule dcr = DirectoryServer.getSchema().getDITContentRule(oc);
    assertNotNull(dcr);
    assertTrue(dcr.hasName("testadddcrtoaltschemafile"));
    assertTrue(schemaFile.exists());
  }
  /**
   * Tests the behavior of the schema backend when attempting to remove an
   * existing DIT content rule and add it back in the same operation.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testRemoveThenAddDITContentRule()
         throws Exception
  {
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "add: objectClasses",
         "objectClasses:  ( testremovethenaddditcontentruleoc-oid " +
              "NAME 'testRemoveThenAddDITContentRuleOC' SUP top " +
              "STRUCTURAL MUST cn X-ORIGIN 'SchemaBackendTestCase')",
         "-",
         "add: ditContentRules",
         "ditContentRules: ( testremovethenaddditcontentruleoc-oid " +
              "NAME 'testRemoveThenAddDITContentRule' NOT description " +
              "X-ORIGIN 'SchemaBackendTestCase' )",
         "",
         "dn: cn=schema",
         "changetype: modify",
         "delete: ditContentRules",
         "ditContentRules: ( testremovethenaddditcontentruleoc-oid " +
              "NAME 'testRemoveThenAddDITContentRule' NOT description " +
              "X-ORIGIN 'SchemaBackendTestCase' )",
         "-",
         "add: ditContentRules",
         "ditContentRules: ( testremovethenaddditcontentruleoc-oid " +
              "NAME 'testRemoveThenAddDITContentRule' MAY sn " +
              "NOT description X-ORIGIN 'SchemaBackendTestCase' )");
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    String ocName = "testremovethenaddditcontentruleoc";
    assertFalse(DirectoryServer.getSchema().hasObjectClass(ocName));
    assertEquals(LDAPModify.mainModify(args, false, null, System.err), 0);
    ObjectClass oc = DirectoryServer.getSchema().getObjectClass(ocName);
    assertNotNull(oc);
    DITContentRule dcr = DirectoryServer.getSchema().getDITContentRule(oc);
    assertNotNull(dcr);
    assertTrue(dcr.hasName("testremovethenaddditcontentrule"));
  }
  /**
   * Tests the behavior of the schema backend when attempting to add a new DIT
   * content rule whose structural objectclass is not defined in the schema.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testAddDITContentRuleUndefinedOC()
         throws Exception
  {
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "add: ditContentRules",
         "ditContentRules: ( xxxundefinedxxx-oid " +
              "NAME 'testAddDITContentRuleUndefinedOC' NOT description " +
              "X-ORIGIN 'SchemaBackendTestCase' )");
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    assertFalse(LDAPModify.mainModify(args, false, null, null) == 0);
  }
  /**
   * Tests the behavior of the schema backend when attempting to add a new DIT
   * content rule whose structural objectclass is not actually structural.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testAddDITContentRuleAuxiliaryOC()
         throws Exception
  {
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "add: objectClasses",
         "objectClasses:  ( testaddditcontentruleauxiliaryococ-oid " +
              "NAME 'testAddDITContentRuleAuxiliaryOCOC' SUP top AUXILIARY " +
              "MUST cn X-ORIGIN 'SchemaBackendTestCase')",
         "-",
         "add: ditContentRules",
         "ditContentRules: ( testaddditcontentruleauxiliaryococ-oid " +
              "NAME 'testAddDITContentRuleAuxiliaryOC' NOT description " +
              "X-ORIGIN 'SchemaBackendTestCase' )");
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    assertFalse(LDAPModify.mainModify(args, false, null, null) == 0);
  }
  /**
   * Tests the behavior of the schema backend when attempting to add a new DIT
   * content rule whose structural objectclass is already referenced by an
   * existing DIT content rule.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testAddDITContentRuleConflictingOC()
         throws Exception
  {
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "add: objectClasses",
         "objectClasses:  ( testaddditcontentruleconflictingococ-oid " +
              "NAME 'testAddDITContentRuleConflictingOCOC' SUP top " +
              "STRUCTURAL MUST cn X-ORIGIN 'SchemaBackendTestCase')",
         "-",
         "add: ditContentRules",
         "ditContentRules: ( testaddditcontentruleconflictingococ-oid " +
              "NAME 'testAddDITContentRuleConflictingOC' NOT description " +
              "X-ORIGIN 'SchemaBackendTestCase' )",
         "",
         "dn: cn=schema",
         "changetype: modify",
         "add: ditContentRules",
         "ditContentRules: ( testaddditcontentruleconflictingococ-oid " +
              "NAME 'testAddDITContentRuleConflictingOC2' NOT description " +
              "X-ORIGIN 'SchemaBackendTestCase' )");
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    assertFalse(LDAPModify.mainModify(args, false, null, null) == 0);
  }
  /**
   * Tests the behavior of the schema backend when attempting to add a new DIT
   * content rule with an undefined auxiliary objectclass.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testAddDITContentRuleUndefinedAuxOC()
         throws Exception
  {
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "add: objectClasses",
         "objectClasses:  ( testaddditcontentruleundefinedauxococ-oid " +
              "NAME 'testAddDITContentRuleUndefinedAuxOCOC' SUP top " +
              "STRUCTURAL MUST cn X-ORIGIN 'SchemaBackendTestCase')",
         "-",
         "add: ditContentRules",
         "ditContentRules: ( testaddditcontentruleundefinedauxococ-oid " +
              "NAME 'testAddDITContentRuleUndefinedAuxOC' " +
              "AUX xxxundefinedxxx X-ORIGIN 'SchemaBackendTestCase' )");
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    assertFalse(LDAPModify.mainModify(args, false, null, null) == 0);
  }
  /**
   * Tests the behavior of the schema backend when attempting to add a new DIT
   * content rule that references an undefined required attribute type.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testAddDITContentRuleUndefinedReqAT()
         throws Exception
  {
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "add: objectClasses",
         "objectClasses:  ( testaddditcontentruleundefinedreqatoc-oid " +
              "NAME 'testAddDITContentRuleAuxiliaryOCOC' SUP top STRUCTURAL " +
              "MUST cn X-ORIGIN 'SchemaBackendTestCase')",
         "-",
         "add: ditContentRules",
         "ditContentRules: ( testaddditcontentruleundefinedreqatoc-oid " +
              "NAME 'testAddDITContentRuleUndefinedReqAT' " +
              "MUST xxxundefinedxxx X-ORIGIN 'SchemaBackendTestCase' )");
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    assertFalse(LDAPModify.mainModify(args, false, null, null) == 0);
  }
  /**
   * Tests the behavior of the schema backend when attempting to add a new DIT
   * content rule that references an undefined optional attribute type.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testAddDITContentRuleUndefinedOptAT()
         throws Exception
  {
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "add: objectClasses",
         "objectClasses:  ( testaddditcontentruleundefinedoptatoc-oid " +
              "NAME 'testAddDITContentRuleAuxiliaryOCOC' SUP top STRUCTURAL " +
              "MUST cn X-ORIGIN 'SchemaBackendTestCase')",
         "-",
         "add: ditContentRules",
         "ditContentRules: ( testaddditcontentruleundefinedoptatoc-oid " +
              "NAME 'testAddDITContentRuleUndefinedOptAT' " +
              "MAY xxxundefinedxxx X-ORIGIN 'SchemaBackendTestCase' )");
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    assertFalse(LDAPModify.mainModify(args, false, null, null) == 0);
  }
  /**
   * Tests the behavior of the schema backend when attempting to add a new DIT
   * content rule that references an undefined prohibited attribute type.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testAddDITContentRuleUndefinedNotAT()
         throws Exception
  {
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "add: objectClasses",
         "objectClasses:  ( testaddditcontentruleundefinednotatoc-oid " +
              "NAME 'testAddDITContentRuleAuxiliaryOCOC' SUP top STRUCTURAL " +
              "MUST cn X-ORIGIN 'SchemaBackendTestCase')",
         "-",
         "add: ditContentRules",
         "ditContentRules: ( testaddditcontentruleundefinednotatoc-oid " +
              "NAME 'testAddDITContentRuleUndefinedNotAT' " +
              "NOT xxxundefinedxxx X-ORIGIN 'SchemaBackendTestCase' )");
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    assertFalse(LDAPModify.mainModify(args, false, null, null) == 0);
  }
  /**
   * Tests the behavior of the schema backend when attempting to remove an
   * existing DIT content rule.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testRemoveDITContentRuleSuccessful()
         throws Exception
  {
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "add: objectClasses",
         "objectClasses:  ( testremoveditcontentrulesuccessfuloc-oid " +
              "NAME 'testRemoveDITContentRuleSuccessfulOC' SUP top " +
              "STRUCTURAL MUST cn X-ORIGIN 'SchemaBackendTestCase')",
         "-",
         "add: ditContentRules",
         "ditContentRules: ( testremoveditcontentrulesuccessfuloc-oid " +
              "NAME 'testRemoveDITContentRuleSuccessful' NOT description " +
              "X-ORIGIN 'SchemaBackendTestCase' )",
         "",
         "dn: cn=schema",
         "changetype: modify",
         "delete: ditContentRules",
         "ditContentRules: ( testremoveditcontentrulesuccessfuloc-oid " +
              "NAME 'testRemoveDITContentRuleSuccessful' NOT description " +
              "X-ORIGIN 'SchemaBackendTestCase' )");
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    String ocName = "testremoveditcontentrulesuccessfuloc";
    assertFalse(DirectoryServer.getSchema().hasObjectClass(ocName));
    assertEquals(LDAPModify.mainModify(args, false, null, System.err), 0);
    ObjectClass oc = DirectoryServer.getSchema().getObjectClass(ocName);
    assertNotNull(oc);
    DITContentRule dcr = DirectoryServer.getSchema().getDITContentRule(oc);
    assertNull(dcr);
  }
  /**
   * Tests the behavior of the schema backend when attempting to add a new
   * DIT structure rule.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testAddDITStructureRuleSuccessful()
         throws Exception
  {
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "add: objectClasses",
         "objectClasses:  ( testaddditstructurerulesuccessfuloc-oid " +
              "NAME 'testAddDITStructureRuleSuccessfulOC' SUP top " +
              "STRUCTURAL MUST cn X-ORIGIN 'SchemaBackendTestCase')",
         "-",
         "add: nameForms",
         "nameForms: ( testaddditstructurerulesuccessfulnf-oid " +
              "NAME 'testAddDITStructureRuleSuccessfulNF' " +
              "OC testAddDITStructureRuleSuccessfulOC MUST cn " +
              "X-ORIGIN 'SchemaBackendTestCase' )",
         "-",
         "add: ditStructureRules",
         "ditStructureRules: ( 999001 " +
              "NAME 'testAddDITStructureRuleSuccessful' " +
              "FORM testAddDITStructureRuleSuccessfulNF " +
              "X-ORIGIN 'SchemaBackendTestCase' )");
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    int ruleID = 999001;
    assertFalse(DirectoryServer.getSchema().hasDITStructureRule(ruleID));
    assertEquals(LDAPModify.mainModify(args, false, null, System.err), 0);
    assertTrue(DirectoryServer.getSchema().hasDITStructureRule(ruleID));
  }
  /**
   * Tests the behavior of the schema backend when attempting to replace an
   * existing DIT structure rule definition.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testReplaceDITStructureRuleSuccessful()
         throws Exception
  {
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "add: objectClasses",
         "objectClasses:  ( testreplaceditstructurerulesuccessfuloc-oid " +
              "NAME 'testReplaceDITStructureRuleSuccessfulOC' SUP top " +
              "STRUCTURAL MUST cn X-ORIGIN 'SchemaBackendTestCase')",
         "-",
         "add: nameForms",
         "nameForms: ( testreplaceditstructurerulesuccessfulnf-oid " +
              "NAME 'testReplaceDITStructureRuleSuccessfulNF' " +
              "OC testReplaceDITStructureRuleSuccessfulOC MUST cn " +
              "X-ORIGIN 'SchemaBackendTestCase' )",
         "-",
         "add: ditStructureRules",
         "ditStructureRules: ( 999002 " +
              "NAME 'testReplaceDITStructureRuleSuccessful' " +
              "FORM testReplaceDITStructureRuleSuccessfulNF " +
              "X-ORIGIN 'SchemaBackendTestCase' )",
         "",
         "dn: cn=schema",
         "changetype: modify",
         "add: ditStructureRules",
         "ditStructureRules: ( 999002 " +
              "NAME 'testReplaceDITStructureRuleSuccessful' " +
              "DESC 'Testing the replacement of an existing DSR' " +
              "FORM testReplaceDITStructureRuleSuccessfulNF " +
              "X-ORIGIN 'SchemaBackendTestCase' )");
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    int ruleID = 999002;
    assertFalse(DirectoryServer.getSchema().hasDITStructureRule(ruleID));
    assertEquals(LDAPModify.mainModify(args, false, null, System.err), 0);
    assertTrue(DirectoryServer.getSchema().hasDITStructureRule(ruleID));
  }
  /**
   * Tests the behavior of the schema backend when attempting to add a new
   * DIT structure rule to an alternate schema file.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testAddDITStructureRuleToAltSchemaFile()
         throws Exception
  {
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "add: objectClasses",
         "objectClasses:  ( testaddditstructureruletoaltschemafileoc-oid " +
              "NAME 'testAddDITStructureRuleToAltSchemaFileOC' SUP top " +
              "STRUCTURAL MUST cn X-SCHEMA-FILE '98-schema-test-dsr.ldif' " +
              "X-ORIGIN 'SchemaBackendTestCase')",
         "-",
         "add: nameForms",
         "nameForms: ( testaddditstructureruletoaltschemafilenf-oid " +
              "NAME 'testAddDITStructureRuleToAltSchemaFileNF' " +
              "OC testAddDITStructureRuleToAltSchemaFileOC MUST cn " +
              "X-SCHEMA-FILE '98-schema-test-dsr.ldif' " +
              "X-ORIGIN 'SchemaBackendTestCase' )",
         "-",
         "add: ditStructureRules",
         "ditStructureRules: ( 999010 " +
              "NAME 'testAddDITStructureRuleToAltSchemaFile' " +
              "FORM testAddDITStructureRuleToAltSchemaFileNF " +
              "X-SCHEMA-FILE '98-schema-test-dsr.ldif' " +
              "X-ORIGIN 'SchemaBackendTestCase' )");
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    int ruleID = 999010;
    assertFalse(DirectoryServer.getSchema().hasDITStructureRule(ruleID));
    File schemaFile = new File(SchemaConfigManager.getSchemaDirectoryPath(),
                               "98-schema-test-dsr.ldif");
    assertFalse(schemaFile.exists());
    assertEquals(LDAPModify.mainModify(args, false, null, System.err), 0);
    assertTrue(DirectoryServer.getSchema().hasDITStructureRule(ruleID));
    assertTrue(schemaFile.exists());
  }
  /**
   * Tests the behavior of the schema backend when attempting to remove an
   * existing DIT structure rule definition and add it back in the same
   * operation.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testRemoveAndAddDITStructureRuleSuccessful()
         throws Exception
  {
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "add: objectClasses",
         "objectClasses:  ( testremoveandaddditstructurerulesuccessfuloc-oid " +
              "NAME 'testRemoveAndAddDITStructureRuleSuccessfulOC' SUP top " +
              "STRUCTURAL MUST cn X-ORIGIN 'SchemaBackendTestCase')",
         "-",
         "add: nameForms",
         "nameForms: ( testremoveandaddditstructurerulesuccessfulnf-oid " +
              "NAME 'testRemoveAndAddDITStructureRuleSuccessfulNF' " +
              "OC testRemoveAndAddDITStructureRuleSuccessfulOC MUST cn " +
              "X-ORIGIN 'SchemaBackendTestCase' )",
         "-",
         "add: ditStructureRules",
         "ditStructureRules: ( 999003 " +
              "NAME 'testRemoveAndAddDITStructureRuleSuccessful' " +
              "FORM testRemoveAndAddDITStructureRuleSuccessfulNF " +
              "X-ORIGIN 'SchemaBackendTestCase' )",
         "",
         "dn: cn=schema",
         "changetype: modify",
         "delete: ditStructureRules",
         "ditStructureRules: ( 999003 " +
              "NAME 'testRemoveAndAddDITStructureRuleSuccessful' " +
              "FORM testRemoveAndAddDITStructureRuleSuccessfulNF " +
              "X-ORIGIN 'SchemaBackendTestCase' )",
         "-",
         "add: ditStructureRules",
         "ditStructureRules: ( 999003 " +
              "NAME 'testRemoveAndAddDITStructureRuleSuccessful' " +
              "DESC 'Testing removing and re-adding an existing DSR' " +
              "FORM testRemoveAndAddDITStructureRuleSuccessfulNF " +
              "X-ORIGIN 'SchemaBackendTestCase' )");
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    int ruleID = 999003;
    assertFalse(DirectoryServer.getSchema().hasDITStructureRule(ruleID));
    assertEquals(LDAPModify.mainModify(args, false, null, System.err), 0);
    assertTrue(DirectoryServer.getSchema().hasDITStructureRule(ruleID));
  }
  /**
   * Tests the behavior of the schema backend when attempting to add a new
   * DIT structure rule with an undefined name form.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testAddDITStructureRuleUndefinedNameForm()
         throws Exception
  {
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "add: ditStructureRules",
         "ditStructureRules: ( 999004 " +
              "NAME 'testAddDITStructureRuleUndefinedNameForm' " +
              "FORM xxxundefinedxxx " +
              "X-ORIGIN 'SchemaBackendTestCase' )");
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    int ruleID = 999004;
    assertFalse(DirectoryServer.getSchema().hasDITStructureRule(ruleID));
    assertFalse(LDAPModify.mainModify(args, false, null, null) == 0);
    assertFalse(DirectoryServer.getSchema().hasDITStructureRule(ruleID));
  }
  /**
   * Tests the behavior of the schema backend when attempting to add a new
   * DIT structure rule that references an undefined superior rule.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testAddDITStructureRuleUndefinedSuperior()
         throws Exception
  {
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "add: objectClasses",
         "objectClasses:  ( testadddsrundefinedsuperioroc-oid " +
              "NAME 'testAddDSRUndefinedSuperiorOC' SUP top " +
              "STRUCTURAL MUST cn X-ORIGIN 'SchemaBackendTestCase')",
         "-",
         "add: nameForms",
         "nameForms: ( testadddsrundefinedsuperiornf-oid " +
              "NAME 'testAddDSRUndefinedSuperiorNF' " +
              "OC testAddDSRUndefinedSuperiorOC MUST cn " +
              "X-ORIGIN 'SchemaBackendTestCase' )",
         "-",
         "add: ditStructureRules",
         "ditStructureRules: ( 999005 " +
              "NAME 'testAddDSRUndefinedSuperior' " +
              "FORM testAddDSRUndefinedSuperiorNF SUP 999000 " +
              "X-ORIGIN 'SchemaBackendTestCase' )");
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    int ruleID = 999005;
    assertFalse(DirectoryServer.getSchema().hasDITStructureRule(ruleID));
    assertFalse(LDAPModify.mainModify(args, false, null, null) == 0);
    assertFalse(DirectoryServer.getSchema().hasDITStructureRule(ruleID));
  }
  /**
   * Tests the behavior of the schema backend when attempting to remove an
   * existing DIT structure rule definition.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testRemoveDITStructureRuleSuccessful()
         throws Exception
  {
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "add: objectClasses",
         "objectClasses:  ( testremoveditstructurerulesuccessfuloc-oid " +
              "NAME 'testRemoveDITStructureRuleSuccessfulOC' SUP top " +
              "STRUCTURAL MUST cn X-ORIGIN 'SchemaBackendTestCase')",
         "-",
         "add: nameForms",
         "nameForms: ( testremoveditstructurerulesuccessfulnf-oid " +
              "NAME 'testRemoveDITStructureRuleSuccessfulNF' " +
              "OC testRemoveDITStructureRuleSuccessfulOC MUST cn " +
              "X-ORIGIN 'SchemaBackendTestCase' )",
         "-",
         "add: ditStructureRules",
         "ditStructureRules: ( 999006 " +
              "NAME 'testRemoveDITStructureRuleSuccessful' " +
              "FORM testRemoveDITStructureRuleSuccessfulNF " +
              "X-ORIGIN 'SchemaBackendTestCase' )",
         "",
         "dn: cn=schema",
         "changetype: modify",
         "delete: ditStructureRules",
         "ditStructureRules: ( 999006 " +
              "NAME 'testRemoveDITStructureRuleSuccessful' " +
              "FORM testRemoveDITStructureRuleSuccessfulNF " +
              "X-ORIGIN 'SchemaBackendTestCase' )");
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    int ruleID = 999006;
    assertFalse(DirectoryServer.getSchema().hasDITStructureRule(ruleID));
    assertEquals(LDAPModify.mainModify(args, false, null, System.err), 0);
    assertFalse(DirectoryServer.getSchema().hasDITStructureRule(ruleID));
  }
  /**
   * Tests the behavior of the schema backend when attempting to remove an
   * existing DIT structure rule definition which is the superior rule for
   * another DIT structure rule.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testRemoveSuperiorDITStructureRule()
         throws Exception
  {
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "add: objectClasses",
         "objectClasses:  ( testremovesuperiorditstructureruleoc-oid " +
              "NAME 'testRemoveSuperiorDITStructureRuleOC' SUP top " +
              "STRUCTURAL MUST cn X-ORIGIN 'SchemaBackendTestCase')",
         "objectClasses:  ( testremovesuperiorditstructureruleoc2-oid " +
              "NAME 'testRemoveSuperiorDITStructureRuleOC2' SUP top " +
              "STRUCTURAL MUST cn X-ORIGIN 'SchemaBackendTestCase')",
         "-",
         "add: nameForms",
         "nameForms: ( testremovesuperiorditstructurerulenf-oid " +
              "NAME 'testRemoveSuperiorDITStructureRuleNF' " +
              "OC testRemoveSuperiorDITStructureRuleOC MUST cn " +
              "X-ORIGIN 'SchemaBackendTestCase' )",
         "nameForms: ( testremovesuperiorditstructurerulenf2-oid " +
              "NAME 'testRemoveSuperiorDITStructureRuleNF2' " +
              "OC testRemoveSuperiorDITStructureRuleOC2 MUST cn " +
              "X-ORIGIN 'SchemaBackendTestCase' )",
         "-",
         "add: ditStructureRules",
         "ditStructureRules: ( 999007 " +
              "NAME 'testRemoveSuperiorDITStructureRule' " +
              "FORM testRemoveSuperiorDITStructureRuleNF " +
              "X-ORIGIN 'SchemaBackendTestCase' )",
         "ditStructureRules: ( 999008 " +
              "NAME 'testRemoveSuperiorDITStructureRule2' " +
              "FORM testRemoveSuperiorDITStructureRuleNF2 SUP 999007 " +
              "X-ORIGIN 'SchemaBackendTestCase' )",
         "",
         "dn: cn=schema",
         "changetype: modify",
         "delete: ditStructureRules",
         "ditStructureRules: ( 999007 " +
              "NAME 'testRemoveSuperiorDITStructureRule' " +
              "FORM testRemoveSuperiorDITStructureRuleNF " +
              "X-ORIGIN 'SchemaBackendTestCase' )");
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    int ruleID = 999007;
    assertFalse(DirectoryServer.getSchema().hasDITStructureRule(ruleID));
    assertFalse(LDAPModify.mainModify(args, false, null, null) == 0);
    assertTrue(DirectoryServer.getSchema().hasDITStructureRule(ruleID));
    path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "delete: ditStructureRules",
         "ditStructureRules: ( 999008 " +
              "NAME 'testRemoveSuperiorDITStructureRule2' " +
              "FORM testRemoveSuperiorDITStructureRuleNF2 SUP 999007 " +
              "X-ORIGIN 'SchemaBackendTestCase' )",
         "ditStructureRules: ( 999007 " +
              "NAME 'testRemoveSuperiorDITStructureRule' " +
              "FORM testRemoveSuperiorDITStructureRuleNF " +
              "X-ORIGIN 'SchemaBackendTestCase' )");
    args = new String[]
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    assertEquals(LDAPModify.mainModify(args, false, null, System.err), 0);
    assertFalse(DirectoryServer.getSchema().hasDITStructureRule(ruleID));
  }
  /**
   * Tests the behavior of the schema backend when attempting to add a new
   * matching rule use that doesn't already exist.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testAddMatchingRuleUseSuccessful()
         throws Exception
  {
    SchemaTestMatchingRule matchingRule =
         new SchemaTestMatchingRule("testAddMRUSuccessfulMatch",
                                    "1.3.6.1.4.1.26027.1.999.10");
    DirectoryServer.registerMatchingRule(matchingRule, false);
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "add: matchingRuleUse",
         "matchingRuleUse: ( 1.3.6.1.4.1.26027.1.999.10 " +
              "NAME 'testAddMRUSuccessful' APPLIES cn " +
              "X-ORIGIN 'SchemaBackendTestCase' )");
    assertFalse(DirectoryServer.getSchema().hasMatchingRuleUse(matchingRule));
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    assertEquals(LDAPModify.mainModify(args, false, null, System.err), 0);
    MatchingRuleUse mru =
         DirectoryServer.getSchema().getMatchingRuleUse(matchingRule);
    assertNotNull(mru);
    assertTrue(mru.hasName("testaddmrusuccessful"));
  }
  /**
   * Tests the behavior of the schema backend when attempting to add a new
   * matching rule to an alternate schema file.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testAddMatchingRuleUseToAltSchemaFile()
         throws Exception
  {
    SchemaTestMatchingRule matchingRule =
         new SchemaTestMatchingRule("testAddMRUToAltSchemaFileMatch",
                                    "1.3.6.1.4.1.26027.1.999.18");
    DirectoryServer.registerMatchingRule(matchingRule, false);
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "add: matchingRuleUse",
         "matchingRuleUse: ( 1.3.6.1.4.1.26027.1.999.18 " +
              "NAME 'testAddMRUToAltSchemaFile' APPLIES cn " +
              "X-SCHEMA-FILE '98-schema-test-mru.ldif' " +
              "X-ORIGIN 'SchemaBackendTestCase' )");
    assertFalse(DirectoryServer.getSchema().hasMatchingRuleUse(matchingRule));
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    File schemaFile = new File(SchemaConfigManager.getSchemaDirectoryPath(),
                               "98-schema-test-mru.ldif");
    assertFalse(schemaFile.exists());
    assertEquals(LDAPModify.mainModify(args, false, null, System.err), 0);
    MatchingRuleUse mru =
         DirectoryServer.getSchema().getMatchingRuleUse(matchingRule);
    assertNotNull(mru);
    assertTrue(mru.hasName("testaddmrutoaltschemafile"));
    assertTrue(schemaFile.exists());
  }
  /**
   * Tests the behavior of the schema backend when attempting to replace an
   * existing matching rule use.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testReplaceMatchingRuleUseSuccessful()
         throws Exception
  {
    SchemaTestMatchingRule matchingRule =
         new SchemaTestMatchingRule("testReplaceMRUSuccessfulMatch",
                                    "1.3.6.1.4.1.26027.1.999.11");
    DirectoryServer.registerMatchingRule(matchingRule, false);
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "add: matchingRuleUse",
         "matchingRuleUse: ( 1.3.6.1.4.1.26027.1.999.11 " +
              "NAME 'testReplaceMRUSuccessful' APPLIES cn " +
              "X-ORIGIN 'SchemaBackendTestCase' )",
         "",
         "dn: cn=schema",
         "changetype: modify",
         "add: matchingRuleUse",
         "matchingRuleUse: ( 1.3.6.1.4.1.26027.1.999.11 " +
              "NAME 'testReplaceMRUSuccessful' APPLIES ( cn $ sn ) " +
              "X-ORIGIN 'SchemaBackendTestCase' )");
    assertFalse(DirectoryServer.getSchema().hasMatchingRuleUse(matchingRule));
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    assertEquals(LDAPModify.mainModify(args, false, null, System.err), 0);
    MatchingRuleUse mru =
         DirectoryServer.getSchema().getMatchingRuleUse(matchingRule);
    assertNotNull(mru);
    assertTrue(mru.hasName("testreplacemrusuccessful"));
  }
  /**
   * Tests the behavior of the schema backend when attempting to remove and
   * re-add an existing matching rule use in the same operation.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testRemoveAndAddMatchingRuleUse()
         throws Exception
  {
    SchemaTestMatchingRule matchingRule =
         new SchemaTestMatchingRule("testRemoveAndAddMRUMatch",
                                    "1.3.6.1.4.1.26027.1.999.12");
    DirectoryServer.registerMatchingRule(matchingRule, false);
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "add: matchingRuleUse",
         "matchingRuleUse: ( 1.3.6.1.4.1.26027.1.999.12 " +
              "NAME 'testRemoveAndAddMRU' APPLIES cn " +
              "X-ORIGIN 'SchemaBackendTestCase' )",
         "",
         "dn: cn=schema",
         "changetype: modify",
         "delete: matchingRuleUse",
         "matchingRuleUse: ( 1.3.6.1.4.1.26027.1.999.12 " +
              "NAME 'testRemoveAndAddMRU' APPLIES cn " +
              "X-ORIGIN 'SchemaBackendTestCase' )",
         "-",
         "add: matchingRuleUse",
         "matchingRuleUse: ( 1.3.6.1.4.1.26027.1.999.12 " +
              "NAME 'testRemoveAndAddMRU' APPLIES ( cn $ sn ) " +
              "X-ORIGIN 'SchemaBackendTestCase' )");
    assertFalse(DirectoryServer.getSchema().hasMatchingRuleUse(matchingRule));
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    assertEquals(LDAPModify.mainModify(args, false, null, System.err), 0);
    MatchingRuleUse mru =
         DirectoryServer.getSchema().getMatchingRuleUse(matchingRule);
    assertNotNull(mru);
    assertTrue(mru.hasName("testremoveandaddmru"));
  }
  /**
   * Tests the behavior of the schema backend when attempting to add a matching
   * rule use that references the same matching rule as another matching rule
   * use.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testAddMatchingRuleUseMRConflict()
         throws Exception
  {
    SchemaTestMatchingRule matchingRule =
         new SchemaTestMatchingRule("testAddMRUMRConflictMatch",
                                    "1.3.6.1.4.1.26027.1.999.14");
    DirectoryServer.registerMatchingRule(matchingRule, false);
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "add: matchingRuleUse",
         "matchingRuleUse: ( 1.3.6.1.4.1.26027.1.999.14 " +
              "NAME 'testAddMRUMRConflict' APPLIES cn " +
              "X-ORIGIN 'SchemaBackendTestCase' )",
         "",
         "dn: cn=schema",
         "changetype: modify",
         "add: matchingRuleUse",
         "matchingRuleUse: ( 1.3.6.1.4.1.26027.1.999.14 " +
              "NAME 'testAddMRUMRConflict2' APPLIES sn " +
              "X-ORIGIN 'SchemaBackendTestCase' )");
    assertFalse(DirectoryServer.getSchema().hasMatchingRuleUse(matchingRule));
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    assertFalse(LDAPModify.mainModify(args, false, null, null) == 0);
    MatchingRuleUse mru =
         DirectoryServer.getSchema().getMatchingRuleUse(matchingRule);
    assertNotNull(mru);
    assertTrue(mru.hasName("testaddmrumrconflict"));
  }
  /**
   * Tests the behavior of the schema backend when attempting to add a new
   * matching rule use that references an undefined matching rule.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testAddMatchingRuleUseMRUndefined()
         throws Exception
  {
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "add: matchingRuleUse",
         "matchingRuleUse: ( 1.3.6.1.4.1.26027.1.999.15 " +
              "NAME 'testAddMRUMRUndefined' APPLIES cn " +
              "X-ORIGIN 'SchemaBackendTestCase' )");
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    assertFalse(LDAPModify.mainModify(args, false, null, null) == 0);
  }
  /**
   * Tests the behavior of the schema backend when attempting to add a new
   * matching rule use that references an undefined attribute type.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testAddMatchingRuleUseAttributeTypeUndefined()
         throws Exception
  {
    SchemaTestMatchingRule matchingRule =
         new SchemaTestMatchingRule("testAddMRUATUndefinedMatch",
                                    "1.3.6.1.4.1.26027.1.999.16");
    DirectoryServer.registerMatchingRule(matchingRule, false);
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "add: matchingRuleUse",
         "matchingRuleUse: ( 1.3.6.1.4.1.26027.1.999.16 " +
              "NAME 'testAddMatchingRuleUseATUndefined' " +
              "APPLIES xxxundefinedxxx " +
              "X-ORIGIN 'SchemaBackendTestCase' )");
    assertFalse(DirectoryServer.getSchema().hasMatchingRuleUse(matchingRule));
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    assertFalse(LDAPModify.mainModify(args, false, null, null) == 0);
  }
  /**
   * Tests the behavior of the schema backend when attempting to remove an
   * existing matching rule use.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testRemoveMatchingRuleUseSuccessful()
         throws Exception
  {
    SchemaTestMatchingRule matchingRule =
         new SchemaTestMatchingRule("testRemoveMRUSuccessfulMatch",
                                    "1.3.6.1.4.1.26027.1.999.13");
    DirectoryServer.registerMatchingRule(matchingRule, false);
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "add: matchingRuleUse",
         "matchingRuleUse: ( 1.3.6.1.4.1.26027.1.999.13 " +
              "NAME 'testRemoveMRUSuccessful' APPLIES cn " +
              "X-ORIGIN 'SchemaBackendTestCase' )",
         "",
         "dn: cn=schema",
         "changetype: modify",
         "delete: matchingRuleUse",
         "matchingRuleUse: ( 1.3.6.1.4.1.26027.1.999.13 " +
              "NAME 'testRemoveMRUSuccessful' APPLIES cn " +
              "X-ORIGIN 'SchemaBackendTestCase' )");
    assertFalse(DirectoryServer.getSchema().hasMatchingRuleUse(matchingRule));
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    assertEquals(LDAPModify.mainModify(args, false, null, System.err), 0);
    MatchingRuleUse mru =
         DirectoryServer.getSchema().getMatchingRuleUse(matchingRule);
    assertNull(mru);
  }
  /**
   * Tests the {@code exportLDIF} method with a valid configuration.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testExportLDIF()
         throws Exception
  {
    DN configEntryDN =
            DN.decode("ds-cfg-backend-id=schema,cn=Backends,cn=config");
    DN[] baseDNs = { DN.decode("cn=schema") };
    ConfigEntry configEntry =
         DirectoryServer.getConfigHandler().getConfigEntry(configEntryDN);
    File tempFile = File.createTempFile("schema", "testExportLDIF");
    tempFile.deleteOnExit();
    LDIFExportConfig exportConfig =
         new LDIFExportConfig(tempFile.getAbsolutePath(),
                              ExistingFileBehavior.OVERWRITE);
    schemaBackend.exportLDIF(configEntry, baseDNs, exportConfig);
    assertTrue(tempFile.exists());
    assertTrue(tempFile.length() > 0);
  }
  /**
   * Tests the {@code importLDIF} method to ensure that it throws an exception.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test(expectedExceptions = { DirectoryException.class })
  public void testImportLDIF()
         throws Exception
  {
    DN configEntryDN =
            DN.decode("ds-cfg-backend-id=schema,cn=Backends,cn=config");
    DN[] baseDNs = { DN.decode("cn=schema") };
    ConfigEntry configEntry =
         DirectoryServer.getConfigHandler().getConfigEntry(configEntryDN);
    File tempFile = File.createTempFile("schema", "testImportLDIF");
    tempFile.deleteOnExit();
    LDIFImportConfig importConfig =
         new LDIFImportConfig(tempFile.getAbsolutePath());
    schemaBackend.importLDIF(configEntry, baseDNs, importConfig);
  }
  /**
   * Tests the {@code getComponentEntryDN} method.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testGetComponentEntryDN()
         throws Exception
  {
    DN configEntryDN =
            DN.decode("ds-cfg-backend-id=schema,cn=Backends,cn=config");
    assertEquals(schemaBackend.getComponentEntryDN(), configEntryDN);
  }
  /**
   * Tests the {@code getClassName} method.
   */
  @Test()
  public void testGetClassName()
  {
    assertEquals(schemaBackend.getClassName(), SchemaBackend.class.getName());
  }
  /**
   * Tests the {@code getAlerts} method.
   */
  @Test()
  public void testGetAlerts()
  {
    LinkedHashMap<String,String> alerts = schemaBackend.getAlerts();
    assertNotNull(alerts);
    assertFalse(alerts.isEmpty());
  }
}
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/backends/SchemaTestMatchingRule.java
New file
@@ -0,0 +1,190 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying * information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2007 Sun Microsystems, Inc.
 */
package org.opends.server.backends;
import org.opends.server.api.EqualityMatchingRule;
import org.opends.server.config.ConfigEntry;
import org.opends.server.config.ConfigException;
import org.opends.server.schema.CaseIgnoreEqualityMatchingRule;
import org.opends.server.types.ByteString;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.InitializationException;
/**
 * This class implements an equality matching rule that is intended for testing
 * purposes within the server (e.g., in conjunction with matching rule uses).
 * For all practical purposes, it behaves like the standard caseIgnoreMatch
 * matching rule.
 */
public class SchemaTestMatchingRule
       extends EqualityMatchingRule
{
  // The matching rule that will do all the real work behind the scenes.
  private CaseIgnoreEqualityMatchingRule caseIgnoreMatchingRule;
  // The name for this matching rule.
  private String name;
  // The OID for this matching rule.
  private String oid;
  /**
   * Creates a new instance of this matching rule with the provided information.
   *
   * @param  name  The name to use for this matching rule.
   * @param  oid   The OID to use for this matching rule.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  public SchemaTestMatchingRule(String name, String oid)
         throws Exception
  {
    super();
    this.name = name;
    this.oid  = oid;
    caseIgnoreMatchingRule = new CaseIgnoreEqualityMatchingRule();
    caseIgnoreMatchingRule.initializeMatchingRule(null);
  }
  /**
   * Initializes this matching rule based on the information in the provided
   * configuration entry.
   *
   * @param  configEntry  The configuration entry that contains the information
   *                      to use to initialize this matching rule.
   *
   * @throws  ConfigException  If an unrecoverable problem arises in the
   *                           process of performing the initialization.
   *
   * @throws  InitializationException  If a problem that is not
   *                                   configuration-related occurs during
   *                                   initialization.
   */
  public void initializeMatchingRule(ConfigEntry configEntry)
         throws ConfigException, InitializationException
  {
    // No initialization is required.
  }
  /**
   * Retrieves the common name for this matching rule.
   *
   * @return  The common name for this matching rule, or <CODE>null</CODE> if
   * it does not have a name.
   */
  public String getName()
  {
    return name;
  }
  /**
   * Retrieves the OID for this matching rule.
   *
   * @return  The OID for this matching rule.
   */
  public String getOID()
  {
    return oid;
  }
  /**
   * Retrieves the description for this matching rule.
   *
   * @return  The description for this matching rule, or <CODE>null</CODE> if
   *          there is none.
   */
  public String getDescription()
  {
    return null;
  }
  /**
   * Retrieves the OID of the syntax with which this matching rule is
   * associated.
   *
   * @return  The OID of the syntax with which this matching rule is associated.
   */
  public String getSyntaxOID()
  {
    return caseIgnoreMatchingRule.getSyntaxOID();
  }
  /**
   * Retrieves the normalized form of the provided value, which is best suited
   * for efficiently performing matching operations on that value.
   *
   * @param  value  The value to be normalized.
   *
   * @return  The normalized version of the provided value.
   *
   * @throws  DirectoryException  If the provided value is invalid according to
   *                              the associated attribute syntax.
   */
  public ByteString normalizeValue(ByteString value)
         throws DirectoryException
  {
    return caseIgnoreMatchingRule.normalizeValue(value);
  }
  /**
   * Indicates whether the two provided normalized values are equal to each
   * other.
   *
   * @param  value1  The normalized form of the first value to compare.
   * @param  value2  The normalized form of the second value to compare.
   *
   * @return  <CODE>true</CODE> if the provided values are equal, or
   *          <CODE>false</CODE> if not.
   */
  public boolean areEqual(ByteString value1, ByteString value2)
  {
    return caseIgnoreMatchingRule.areEqual(value1, value2);
  }
}
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestAttributeType.java
@@ -22,13 +22,15 @@
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2006 Sun Microsystems, Inc.
 *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
 */
package org.opends.server.types;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
@@ -139,12 +141,157 @@
    protected AttributeType buildInstance(String primaryName,
        Collection<String> names, String oid, String description,
        boolean isObsolete, Map<String, List<String>> extraProperties) {
      return new AttributeType(primaryName, names, oid, description,
          superiorType, syntax, approximateMatchingRule,
          equalityMatchingRule, orderingMatchingRule,
          substringMatchingRule, attributeUsage, isCollective,
          isNoUserModification, isObsolete, isSingleValue,
          extraProperties);
      StringBuilder definition = new StringBuilder();
      definition.append("( ");
      definition.append(oid);
      LinkedHashSet<String> nameSet = new LinkedHashSet<String>();
      if (primaryName != null)
      {
        nameSet.add(primaryName);
      }
      if (names != null)
      {
        for (String name : names)
        {
          nameSet.add(name);
        }
      }
      if (! nameSet.isEmpty())
      {
        if (nameSet.size() == 1)
        {
          definition.append(" NAME '");
          definition.append(nameSet.iterator().next());
          definition.append("'");
        }
        else
        {
          Iterator<String> iterator = nameSet.iterator();
          definition.append(" NAME ( '");
          definition.append(iterator.next());
          while (iterator.hasNext())
          {
            definition.append("' '");
            definition.append(iterator.next());
          }
          definition.append("' )");
        }
      }
      if (description != null)
      {
        definition.append(" DESC '");
        definition.append(description);
        definition.append("'");
      }
      if (isObsolete)
      {
        definition.append(" OBSOLETE");
      }
      if (superiorType != null)
      {
        definition.append(" SUP ");
        definition.append(superiorType.getNameOrOID());
      }
      if (equalityMatchingRule != null)
      {
        definition.append(" EQUALITY ");
        definition.append(equalityMatchingRule.getNameOrOID());
      }
      if (orderingMatchingRule != null)
      {
        definition.append(" ORDERING ");
        definition.append(orderingMatchingRule.getNameOrOID());
      }
      if (substringMatchingRule != null)
      {
        definition.append(" SUBSTR ");
        definition.append(substringMatchingRule.getNameOrOID());
      }
      if (syntax != null)
      {
        definition.append(" SYNTAX ");
        definition.append(syntax.getOID());
      }
      if (isSingleValue)
      {
        definition.append(" SINGLE-VALUE");
      }
      if (isCollective)
      {
        definition.append(" COLLECTIVE");
      }
      if (isNoUserModification)
      {
        definition.append(" NO-USER-MODIFICATIOn");
      }
      if (attributeUsage != null)
      {
        definition.append(" USAGE ");
        definition.append(attributeUsage.toString());
      }
      if (extraProperties != null)
      {
        for (String property : extraProperties.keySet())
        {
          List<String> values = extraProperties.get(property);
          if ((values == null) || values.isEmpty())
          {
            continue;
          }
          else if (values.size() == 1)
          {
            definition.append(" ");
            definition.append(property);
            definition.append(" '");
            definition.append(values.get(0));
            definition.append("'");
          }
          else
          {
            definition.append(" ");
            definition.append(property);
            definition.append(" (");
            for (String value : values)
            {
              definition.append(" '");
              definition.append(value);
              definition.append("'");
            }
            definition.append(" )");
          }
        }
      }
      definition.append(" )");
      return new AttributeType(definition.toString(), primaryName, names, oid,
                               description, superiorType, syntax,
                               approximateMatchingRule, equalityMatchingRule,
                               orderingMatchingRule, substringMatchingRule,
                               attributeUsage, isCollective,
                               isNoUserModification, isObsolete, isSingleValue,
                               extraProperties);
    }
@@ -283,7 +430,7 @@
   */
  @Test(expectedExceptions = NullPointerException.class)
  public void testSimpleConstructorNPE() throws Exception {
    new AttributeType(null, null, null, null, null, null, null,
    new AttributeType(null, null, null, null, null, null, null, null,
        false, false, false, false);
  }
@@ -298,7 +445,7 @@
   */
  @Test(expectedExceptions = NullPointerException.class)
  public void testComplexConstructorNPE() throws Exception {
    new AttributeType(null, null, null, null, null, null, null, null,
    new AttributeType(null, null, null, null, null, null, null, null, null,
        null, null, null, false, false, false, false, null);
  }
@@ -313,7 +460,7 @@
   */
  @Test
  public void testComplexConstructorDefault() throws Exception {
    AttributeType type = new AttributeType(null, null, "1.2.3", null,
    AttributeType type = new AttributeType("", null, null, "1.2.3", null,
        null, null, null, null, null, null, null, false, false,
        false, false, null);
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestObjectClass.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2006 Sun Microsystems, Inc.
 *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
 */
package org.opends.server.types;
@@ -31,6 +31,7 @@
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
@@ -112,9 +113,163 @@
    protected ObjectClass buildInstance(String primaryName,
        Collection<String> names, String oid, String description,
        boolean isObsolete, Map<String, List<String>> extraProperties) {
      return new ObjectClass(primaryName, names, oid, description,
          superior, requiredAttributeTypes, optionalAttributeTypes,
          objectClassType, isObsolete, extraProperties);
      StringBuilder definition = new StringBuilder();
      definition.append("( ");
      definition.append(oid);
      LinkedHashSet<String> nameSet = new LinkedHashSet<String>();
      if (primaryName != null)
      {
        nameSet.add(primaryName);
      }
      if (names != null)
      {
        for (String name : names)
        {
          nameSet.add(name);
        }
      }
      if (! nameSet.isEmpty())
      {
        if (nameSet.size() == 1)
        {
          definition.append(" NAME '");
          definition.append(nameSet.iterator().next());
          definition.append("'");
        }
        else
        {
          Iterator<String> iterator = nameSet.iterator();
          definition.append(" NAME ( '");
          definition.append(iterator.next());
          while (iterator.hasNext())
          {
            definition.append("' '");
            definition.append(iterator.next());
          }
          definition.append("' )");
        }
      }
      if (description != null)
      {
        definition.append(" DESC '");
        definition.append(description);
        definition.append("'");
      }
      if (isObsolete)
      {
        definition.append(" OBSOLETE");
      }
      if (superior != null)
      {
        definition.append(" SUP ");
        definition.append(superior.getNameOrOID());
      }
      if (objectClassType != null)
      {
        definition.append(" ");
        definition.append(objectClassType.toString());
      }
      if ((requiredAttributeTypes != null) &&
          (! requiredAttributeTypes.isEmpty()))
      {
        if (requiredAttributeTypes.size() == 1)
        {
          definition.append(" MUST ");
          definition.append(
               requiredAttributeTypes.iterator().next().getNameOrOID());
        }
        else
        {
          Iterator<AttributeType> iterator = requiredAttributeTypes.iterator();
          definition.append(" MUST ( ");
          definition.append(iterator.next().getNameOrOID());
          while (iterator.hasNext())
          {
            definition.append(" $ ");
            definition.append(iterator.next().getNameOrOID());
          }
          definition.append(" )");
        }
      }
      if ((optionalAttributeTypes != null) &&
          (! optionalAttributeTypes.isEmpty()))
      {
        if (optionalAttributeTypes.size() == 1)
        {
          definition.append(" MUST ");
          definition.append(
               optionalAttributeTypes.iterator().next().getNameOrOID());
        }
        else
        {
          Iterator<AttributeType> iterator = optionalAttributeTypes.iterator();
          definition.append(" MUST ( ");
          definition.append(iterator.next().getNameOrOID());
          while (iterator.hasNext())
          {
            definition.append(" $ ");
            definition.append(iterator.next().getNameOrOID());
          }
          definition.append(" )");
        }
      }
      if (extraProperties != null)
      {
        for (String property : extraProperties.keySet())
        {
          List<String> values = extraProperties.get(property);
          if ((values == null) || values.isEmpty())
          {
            continue;
          }
          else if (values.size() == 1)
          {
            definition.append(" ");
            definition.append(property);
            definition.append(" '");
            definition.append(values.get(0));
            definition.append("'");
          }
          else
          {
            definition.append(" ");
            definition.append(property);
            definition.append(" (");
            for (String value : values)
            {
              definition.append(" '");
              definition.append(value);
              definition.append("'");
            }
            definition.append(" )");
          }
        }
      }
      definition.append(" )");
      return new ObjectClass(definition.toString(), primaryName, names, oid,
                             description, superior, requiredAttributeTypes,
                             optionalAttributeTypes, objectClassType,
                             isObsolete, extraProperties);
    }
@@ -219,7 +374,7 @@
    Set<AttributeType> emptySet = Collections.emptySet();
    Map<String, List<String>> emptyMap = Collections.emptyMap();
    new ObjectClass("test", Collections.singleton("test"), null,
    new ObjectClass(null, "test", Collections.singleton("test"), null,
        "description", DirectoryServer.getTopObjectClass(), emptySet,
        emptySet, ObjectClassType.STRUCTURAL, false, emptyMap);
  }
@@ -235,7 +390,8 @@
   */
  @Test
  public void testConstructorDefault() throws Exception {
    ObjectClass type = new ObjectClass(null, null, "1.2.3", null,
    String definition = "( 1.2.3 )";
    ObjectClass type = new ObjectClass(definition, null, null, "1.2.3", null,
        null, null, null, null, false, null);
    Assert.assertNull(type.getPrimaryName());