From 7c774e1356257bd64273760740f2464f2d6661fb Mon Sep 17 00:00:00 2001
From: neil_a_wilson <neil_a_wilson@localhost>
Date: Tue, 09 Jan 2007 20:20:30 +0000
Subject: [PATCH] Update the schema backend to provide full support for online schema updates. which includes the following:
---
opends/src/server/org/opends/server/types/DITContentRule.java | 710 +--
opends/src/server/org/opends/server/schema/DITContentRuleSyntax.java | 41
opends/src/server/org/opends/server/types/DITStructureRule.java | 485 +-
opends/src/server/org/opends/server/types/CommonSchemaElements.java | 99
opends/src/server/org/opends/server/schema/MatchingRuleUseSyntax.java | 29
opends/src/server/org/opends/server/schema/ObjectClassSyntax.java | 9
opends/src/server/org/opends/server/messages/CoreMessages.java | 17
opends/src/server/org/opends/server/util/ServerConstants.java | 51
opends/src/server/org/opends/server/types/AttributeType.java | 87
opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestAttributeType.java | 167
opends/src/server/org/opends/server/core/SchemaConfigManager.java | 5
opends/src/server/org/opends/server/plugins/EntryUUIDPlugin.java | 14
opends/src/server/org/opends/server/backends/SchemaBackend.java | 3003 +++++++++++++++-
opends/src/server/org/opends/server/schema/DITStructureRuleSyntax.java | 78
opends/src/server/org/opends/server/types/MatchingRuleUse.java | 452 +-
opends/tests/unit-tests-testng/src/server/org/opends/server/backends/SchemaTestMatchingRule.java | 190 +
opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestObjectClass.java | 168
opends/src/server/org/opends/server/types/SchemaFileElement.java | 107
opends/src/server/org/opends/server/types/NameForm.java | 553 +-
opends/tests/unit-tests-testng/src/server/org/opends/server/backends/SchemaBackendTestCase.java | 3041 +++++++++++++++++
opends/src/server/org/opends/server/schema/NameFormSyntax.java | 34
opends/src/server/org/opends/server/core/DirectoryServer.java | 42
opends/src/server/org/opends/server/types/Schema.java | 264 +
opends/src/server/org/opends/server/schema/AttributeTypeSyntax.java | 14
opends/src/server/org/opends/server/types/ObjectClass.java | 133
opends/src/server/org/opends/server/messages/BackendMessages.java | 800 ++++
opends/resource/schema/00-core.ldif | 28
27 files changed, 8,864 insertions(+), 1,757 deletions(-)
diff --git a/opends/resource/schema/00-core.ldif b/opends/resource/schema/00-core.ldif
index b1e41d2..06db180 100644
--- a/opends/resource/schema/00-core.ldif
+++ b/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' )
diff --git a/opends/src/server/org/opends/server/backends/SchemaBackend.java b/opends/src/server/org/opends/server/backends/SchemaBackend.java
index 59956c5..6b5d099 100644
--- a/opends/src/server/org/opends/server/backends/SchemaBackend.java
+++ b/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;
+ }
}
diff --git a/opends/src/server/org/opends/server/core/DirectoryServer.java b/opends/src/server/org/opends/server/core/DirectoryServer.java
index 6817cbc..f9bb224 100644
--- a/opends/src/server/org/opends/server/core/DirectoryServer.java
+++ b/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);
}
diff --git a/opends/src/server/org/opends/server/core/SchemaConfigManager.java b/opends/src/server/org/opends/server/core/SchemaConfigManager.java
index 81ceeaa..2a50f69 100644
--- a/opends/src/server/org/opends/server/core/SchemaConfigManager.java
+++ b/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);
}
diff --git a/opends/src/server/org/opends/server/messages/BackendMessages.java b/opends/src/server/org/opends/server/messages/BackendMessages.java
index 2c1f81c..eec2341 100644
--- a/opends/src/server/org/opends/server/messages/BackendMessages.java
+++ b/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,
diff --git a/opends/src/server/org/opends/server/messages/CoreMessages.java b/opends/src/server/org/opends/server/messages/CoreMessages.java
index 8d29a84..cdf526f 100644
--- a/opends/src/server/org/opends/server/messages/CoreMessages.java
+++ b/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,
diff --git a/opends/src/server/org/opends/server/plugins/EntryUUIDPlugin.java b/opends/src/server/org/opends/server/plugins/EntryUUIDPlugin.java
index a8767cd..dffb210 100644
--- a/opends/src/server/org/opends/server/plugins/EntryUUIDPlugin.java
+++ b/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);
}
diff --git a/opends/src/server/org/opends/server/schema/AttributeTypeSyntax.java b/opends/src/server/org/opends/server/schema/AttributeTypeSyntax.java
index 8d6fa5c..d692564 100644
--- a/opends/src/server/org/opends/server/schema/AttributeTypeSyntax.java
+++ b/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);
}
diff --git a/opends/src/server/org/opends/server/schema/DITContentRuleSyntax.java b/opends/src/server/org/opends/server/schema/DITContentRuleSyntax.java
index 2fdf746..a8dc05e 100644
--- a/opends/src/server/org/opends/server/schema/DITContentRuleSyntax.java
+++ b/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",
diff --git a/opends/src/server/org/opends/server/schema/DITStructureRuleSyntax.java b/opends/src/server/org/opends/server/schema/DITStructureRuleSyntax.java
index de26f8e..9ebbfd6 100644
--- a/opends/src/server/org/opends/server/schema/DITStructureRuleSyntax.java
+++ b/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",
diff --git a/opends/src/server/org/opends/server/schema/MatchingRuleUseSyntax.java b/opends/src/server/org/opends/server/schema/MatchingRuleUseSyntax.java
index f1bcc1a..e238546 100644
--- a/opends/src/server/org/opends/server/schema/MatchingRuleUseSyntax.java
+++ b/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",
diff --git a/opends/src/server/org/opends/server/schema/NameFormSyntax.java b/opends/src/server/org/opends/server/schema/NameFormSyntax.java
index 1624a4e..c349dc6 100644
--- a/opends/src/server/org/opends/server/schema/NameFormSyntax.java
+++ b/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",
diff --git a/opends/src/server/org/opends/server/schema/ObjectClassSyntax.java b/opends/src/server/org/opends/server/schema/ObjectClassSyntax.java
index d6fd0d5..627ccfb 100644
--- a/opends/src/server/org/opends/server/schema/ObjectClassSyntax.java
+++ b/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);
}
diff --git a/opends/src/server/org/opends/server/types/AttributeType.java b/opends/src/server/org/opends/server/types/AttributeType.java
index f35f8aa..d87e727 100644
--- a/opends/src/server/org/opends/server/types/AttributeType.java
+++ b/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
diff --git a/opends/src/server/org/opends/server/types/CommonSchemaElements.java b/opends/src/server/org/opends/server/types/CommonSchemaElements.java
index 8304121..d91916d 100644
--- a/opends/src/server/org/opends/server/types/CommonSchemaElements.java
+++ b/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.
diff --git a/opends/src/server/org/opends/server/types/DITContentRule.java b/opends/src/server/org/opends/server/types/DITContentRule.java
index 70d11aa..088a9b4 100644
--- a/opends/src/server/org/opends/server/types/DITContentRule.java
+++ b/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(" )");
}
}
diff --git a/opends/src/server/org/opends/server/types/DITStructureRule.java b/opends/src/server/org/opends/server/types/DITStructureRule.java
index aa39250..9046ef2 100644
--- a/opends/src/server/org/opends/server/types/DITStructureRule.java
+++ b/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(" )");
}
}
diff --git a/opends/src/server/org/opends/server/types/MatchingRuleUse.java b/opends/src/server/org/opends/server/types/MatchingRuleUse.java
index 4cef2b5..7190358 100644
--- a/opends/src/server/org/opends/server/types/MatchingRuleUse.java
+++ b/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(" )");
}
}
diff --git a/opends/src/server/org/opends/server/types/NameForm.java b/opends/src/server/org/opends/server/types/NameForm.java
index 6ce5bd0..eb5e8b0 100644
--- a/opends/src/server/org/opends/server/types/NameForm.java
+++ b/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(" )");
}
}
diff --git a/opends/src/server/org/opends/server/types/ObjectClass.java b/opends/src/server/org/opends/server/types/ObjectClass.java
index 8079522..ea7c0c2 100644
--- a/opends/src/server/org/opends/server/types/ObjectClass.java
+++ b/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.
*
diff --git a/opends/src/server/org/opends/server/types/Schema.java b/opends/src/server/org/opends/server/types/Schema.java
index d0ee261..d97b5bd 100644
--- a/opends/src/server/org/opends/server/types/Schema.java
+++ b/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.
diff --git a/opends/src/server/org/opends/server/types/SchemaFileElement.java b/opends/src/server/org/opends/server/types/SchemaFileElement.java
new file mode 100644
index 0000000..ca1ca95
--- /dev/null
+++ b/opends/src/server/org/opends/server/types/SchemaFileElement.java
@@ -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;
+}
+
diff --git a/opends/src/server/org/opends/server/util/ServerConstants.java b/opends/src/server/org/opends/server/util/ServerConstants.java
index d3035d1..5db76e1 100644
--- a/opends/src/server/org/opends/server/util/ServerConstants.java
+++ b/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.
*/
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/backends/SchemaBackendTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/backends/SchemaBackendTestCase.java
index 67c1e2f..1996d52 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/backends/SchemaBackendTestCase.java
+++ b/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());
+ }
}
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/backends/SchemaTestMatchingRule.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/backends/SchemaTestMatchingRule.java
new file mode 100644
index 0000000..14f5b57
--- /dev/null
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/backends/SchemaTestMatchingRule.java
@@ -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);
+ }
+}
+
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestAttributeType.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestAttributeType.java
index 949bfde..d78b714 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestAttributeType.java
+++ b/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);
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestObjectClass.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestObjectClass.java
index 41fc1da..2a5390f 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestObjectClass.java
+++ b/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());
--
Gitblit v1.10.0