From 160491be597f55e22b5d5a11bd0c7c1c6a440104 Mon Sep 17 00:00:00 2001
From: Yannick Lecaillez <yannick.lecaillez@forgerock.com>
Date: Fri, 24 Jun 2016 13:54:17 +0000
Subject: [PATCH] OPENDJ-3157: Schema updates via LDAP can overwrite existing schema.
---
opendj-server-legacy/src/main/java/org/opends/server/core/SchemaConfigManager.java | 53 ++++++++++++-
opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java | 166 ++++++++++++++++++++++++++++++++++++++--
2 files changed, 203 insertions(+), 16 deletions(-)
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java
index a4203a3..fdfc804 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java
@@ -122,6 +122,73 @@
return subschemaDN;
}
+ /** Allows to perform modifications on element's builders before adding the result to this schema builder. */
+ public interface SchemaBuilderHook {
+ /**
+ * Allow to modify the builder before its inclusion in schema.
+ *
+ * @param builder
+ * Schema's element builder.
+ */
+ public void beforeAddSyntax(Syntax.Builder builder);
+
+ /**
+ * Allow to modify the builder before its inclusion in schema.
+ *
+ * @param builder
+ * Schema's element builder.
+ */
+ public void beforeAddAttribute(AttributeType.Builder builder);
+
+ /**
+ * Allow to modify the builder before its inclusion in schema.
+ *
+ * @param builder
+ * Schema's element builder.
+ */
+ public void beforeAddObjectClass(ObjectClass.Builder builder);
+
+ /**
+ * Allow to modify the builder before its inclusion in schema.
+ *
+ * @param builder
+ * Schema's element builder.
+ */
+ public void beforeAddMatchingRuleUse(MatchingRuleUse.Builder builder);
+
+ /**
+ * Allow to modify the builder before its inclusion in schema.
+ *
+ * @param builder
+ * Schema's element builder.
+ */
+ public void beforeAddMatchingRule(MatchingRule.Builder builder);
+
+ /**
+ * Allow to modify the builder before its inclusion in schema.
+ *
+ * @param builder
+ * Schema's element builder.
+ */
+ public void beforeAddDitContentRule(DITContentRule.Builder builder);
+
+ /**
+ * Allow to modify the builder before its inclusion in schema.
+ *
+ * @param builder
+ * Schema's element builder.
+ */
+ public void beforeAddDitStructureRule(DITStructureRule.Builder builder);
+
+ /**
+ * Allow to modify the builder before its inclusion in schema.
+ *
+ * @param builder
+ * Schema's element builder.
+ */
+ public void beforeAddNameForm(NameForm.Builder builder);
+ }
+
private Map<Integer, DITStructureRule> id2StructureRules;
private Map<String, List<AttributeType>> name2AttributeTypes;
private Map<String, List<DITContentRule>> name2ContentRules;
@@ -167,7 +234,7 @@
*/
public SchemaBuilder(final Entry entry) {
preLazyInitBuilder(entry.getName().toString(), null);
- addSchema(entry, true);
+ addSchema(entry, true, null);
}
/**
@@ -218,6 +285,10 @@
* If {@code definition} was {@code null}.
*/
public SchemaBuilder addAttributeType(final String definition, final boolean overwrite) {
+ return addAttributeType(definition, overwrite, null);
+ }
+
+ SchemaBuilder addAttributeType(final String definition, final boolean overwrite, SchemaBuilderHook hook) {
Reject.ifNull(definition);
lazyInitBuilder();
@@ -371,6 +442,9 @@
atBuilder.superiorType(superiorType)
.syntax(syntax);
+ if (hook != null) {
+ hook.beforeAddAttribute(atBuilder);
+ }
return atBuilder.addToSchema(overwrite);
} catch (final DecodeException e) {
final LocalizableMessage msg = ERR_ATTR_SYNTAX_ATTRTYPE_INVALID1.get(definition, e.getMessageObject());
@@ -397,6 +471,10 @@
* If {@code definition} was {@code null}.
*/
public SchemaBuilder addDITContentRule(final String definition, final boolean overwrite) {
+ return addDITContentRule(definition, overwrite, null);
+ }
+
+ SchemaBuilder addDITContentRule(final String definition, final boolean overwrite, SchemaBuilderHook hook) {
Reject.ifNull(definition);
lazyInitBuilder();
@@ -478,6 +556,9 @@
}
}
+ if (hook != null) {
+ hook.beforeAddDitContentRule(contentRuleBuilder);
+ }
return contentRuleBuilder.addToSchema(overwrite);
} catch (final DecodeException e) {
final LocalizableMessage msg = ERR_ATTR_SYNTAX_DCR_INVALID1.get(definition, e.getMessageObject());
@@ -504,6 +585,10 @@
* If {@code definition} was {@code null}.
*/
public SchemaBuilder addDITStructureRule(final String definition, final boolean overwrite) {
+ return addDITStructureRule(definition, overwrite, null);
+ }
+
+ SchemaBuilder addDITStructureRule(final String definition, final boolean overwrite, SchemaBuilderHook hook) {
Reject.ifNull(definition);
lazyInitBuilder();
@@ -585,6 +670,9 @@
}
ruleBuilder.nameForm(nameForm);
+ if (hook != null) {
+ hook.beforeAddDitStructureRule(ruleBuilder);
+ }
return ruleBuilder.addToSchema(overwrite);
} catch (final DecodeException e) {
final LocalizableMessage msg = ERR_ATTR_SYNTAX_DSR_INVALID1.get(definition, e.getMessageObject());
@@ -637,6 +725,10 @@
* If {@code definition} was {@code null}.
*/
public SchemaBuilder addMatchingRule(final String definition, final boolean overwrite) {
+ return addMatchingRule(definition, overwrite, null);
+ }
+
+ SchemaBuilder addMatchingRule(final String definition, final boolean overwrite, SchemaBuilderHook hook) {
Reject.ifNull(definition);
lazyInitBuilder();
@@ -720,6 +812,9 @@
if (syntax == null) {
throw new LocalizedIllegalArgumentException(ERR_ATTR_SYNTAX_MR_NO_SYNTAX.get(definition));
}
+ if (hook != null) {
+ hook.beforeAddMatchingRule(matchingRuleBuilder);
+ }
matchingRuleBuilder.addToSchema(overwrite);
} catch (final DecodeException e) {
final LocalizableMessage msg =
@@ -748,6 +843,10 @@
* If {@code definition} was {@code null}.
*/
public SchemaBuilder addMatchingRuleUse(final String definition, final boolean overwrite) {
+ return addMatchingRuleUse(definition, overwrite, null);
+ }
+
+ SchemaBuilder addMatchingRuleUse(final String definition, final boolean overwrite, SchemaBuilderHook hook) {
Reject.ifNull(definition);
lazyInitBuilder();
@@ -829,6 +928,9 @@
}
useBuilder.attributes(attributes);
+ if (hook != null) {
+ hook.beforeAddMatchingRuleUse(useBuilder);
+ }
return useBuilder.addToSchema(overwrite);
} catch (final DecodeException e) {
final LocalizableMessage msg = ERR_ATTR_SYNTAX_MRUSE_INVALID1.get(definition, e.getMessageObject());
@@ -929,6 +1031,10 @@
* If {@code definition} was {@code null}.
*/
public SchemaBuilder addNameForm(final String definition, final boolean overwrite) {
+ return addNameForm(definition, overwrite, null);
+ }
+
+ SchemaBuilder addNameForm(final String definition, final boolean overwrite, SchemaBuilderHook hook) {
Reject.ifNull(definition);
lazyInitBuilder();
@@ -1027,6 +1133,9 @@
throw new LocalizedIllegalArgumentException(ERR_ATTR_SYNTAX_NAME_FORM_NO_REQUIRED_ATTR.get(definition));
}
+ if (hook != null) {
+ hook.beforeAddNameForm(nameFormBuilder);
+ }
nameFormBuilder.addToSchema(overwrite);
} catch (final DecodeException e) {
final LocalizableMessage msg =
@@ -1246,6 +1355,10 @@
* If {@code definition} was {@code null}.
*/
public SchemaBuilder addObjectClass(final String definition, final boolean overwrite) {
+ return addObjectClass(definition, overwrite, null);
+ }
+
+ SchemaBuilder addObjectClass(final String definition, final boolean overwrite, SchemaBuilderHook hook) {
Reject.ifNull(definition);
lazyInitBuilder();
@@ -1335,6 +1448,9 @@
ERR_ATTR_SYNTAX_OBJECTCLASS_ILLEGAL_TOKEN1.get(definition, tokenName));
}
}
+ if (hook != null) {
+ hook.beforeAddObjectClass(ocBuilder);
+ }
if (EXTENSIBLE_OBJECT_OBJECTCLASS_OID.equals(oid)) {
addObjectClass(newExtensibleObjectObjectClass(
@@ -1411,7 +1527,7 @@
// The call to addSchema will perform copyOnWrite.
final SearchRequest request = getReadSchemaSearchRequest(name);
final Entry entry = connection.searchSingleEntry(request);
- return addSchema(entry, overwrite);
+ return addSchema(entry, overwrite, null);
}
/**
@@ -1430,6 +1546,27 @@
* If {@code entry} was {@code null}.
*/
public SchemaBuilder addSchema(final Entry entry, final boolean overwrite) {
+ return addSchema(entry, overwrite, null);
+ }
+
+ /**
+ * Adds all of the schema elements contained in the provided subschema
+ * subentry to this schema builder. Any problems encountered while parsing
+ * the entry can be retrieved using the returned schema's
+ * {@link Schema#getWarnings()} method.
+ *
+ * @param entry
+ * The subschema subentry to be parsed.
+ * @param overwrite
+ * {@code true} if existing schema elements with the same
+ * conflicting OIDs should be overwritten.
+ * @param hook
+ * Allows to perform modifications on element's builders before adding the result to this schema builder.
+ * @return A reference to this schema builder.
+ * @throws NullPointerException
+ * If {@code entry} was {@code null}.
+ */
+ public SchemaBuilder addSchema(final Entry entry, final boolean overwrite, SchemaBuilderHook hook) {
Reject.ifNull(entry);
lazyInitBuilder();
@@ -1438,7 +1575,7 @@
if (attr != null) {
for (final ByteString def : attr) {
try {
- addSyntax(def.toString(), overwrite);
+ addSyntax(def.toString(), overwrite, hook);
} catch (final LocalizedIllegalArgumentException e) {
warnings.add(e.getMessageObject());
}
@@ -1449,7 +1586,7 @@
if (attr != null) {
for (final ByteString def : attr) {
try {
- addAttributeType(def.toString(), overwrite);
+ addAttributeType(def.toString(), overwrite, hook);
} catch (final LocalizedIllegalArgumentException e) {
warnings.add(e.getMessageObject());
}
@@ -1460,7 +1597,7 @@
if (attr != null) {
for (final ByteString def : attr) {
try {
- addObjectClass(def.toString(), overwrite);
+ addObjectClass(def.toString(), overwrite, hook);
} catch (final LocalizedIllegalArgumentException e) {
warnings.add(e.getMessageObject());
}
@@ -1471,7 +1608,7 @@
if (attr != null) {
for (final ByteString def : attr) {
try {
- addMatchingRuleUse(def.toString(), overwrite);
+ addMatchingRuleUse(def.toString(), overwrite, hook);
} catch (final LocalizedIllegalArgumentException e) {
warnings.add(e.getMessageObject());
}
@@ -1482,7 +1619,7 @@
if (attr != null) {
for (final ByteString def : attr) {
try {
- addMatchingRule(def.toString(), overwrite);
+ addMatchingRule(def.toString(), overwrite, hook);
} catch (final LocalizedIllegalArgumentException e) {
warnings.add(e.getMessageObject());
}
@@ -1493,7 +1630,7 @@
if (attr != null) {
for (final ByteString def : attr) {
try {
- addDITContentRule(def.toString(), overwrite);
+ addDITContentRule(def.toString(), overwrite, hook);
} catch (final LocalizedIllegalArgumentException e) {
warnings.add(e.getMessageObject());
}
@@ -1504,7 +1641,7 @@
if (attr != null) {
for (final ByteString def : attr) {
try {
- addDITStructureRule(def.toString(), overwrite);
+ addDITStructureRule(def.toString(), overwrite, hook);
} catch (final LocalizedIllegalArgumentException e) {
warnings.add(e.getMessageObject());
}
@@ -1515,7 +1652,7 @@
if (attr != null) {
for (final ByteString def : attr) {
try {
- addNameForm(def.toString(), overwrite);
+ addNameForm(def.toString(), overwrite, hook);
} catch (final LocalizedIllegalArgumentException e) {
warnings.add(e.getMessageObject());
}
@@ -1582,7 +1719,7 @@
new Function<SearchResultEntry, SchemaBuilder, LdapException>() {
@Override
public SchemaBuilder apply(SearchResultEntry result) throws LdapException {
- addSchema(result, overwrite);
+ addSchema(result, overwrite, null);
return SchemaBuilder.this;
}
});
@@ -1718,6 +1855,10 @@
* If {@code definition} was {@code null}.
*/
public SchemaBuilder addSyntax(final String definition, final boolean overwrite) {
+ return addSyntax(definition, overwrite, null);
+ }
+
+ SchemaBuilder addSyntax(final String definition, final boolean overwrite, SchemaBuilderHook hook) {
Reject.ifNull(definition);
lazyInitBuilder();
@@ -1784,6 +1925,9 @@
}
}
+ if (hook != null) {
+ hook.beforeAddSyntax(syntaxBuilder);
+ }
syntaxBuilder.addToSchema(overwrite);
} catch (final DecodeException e) {
final LocalizableMessage msg =
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/core/SchemaConfigManager.java b/opendj-server-legacy/src/main/java/org/opends/server/core/SchemaConfigManager.java
index c2fec3e..a47679c 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/core/SchemaConfigManager.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/core/SchemaConfigManager.java
@@ -36,7 +36,16 @@
import org.forgerock.opendj.ldap.ResultCode;
import org.forgerock.opendj.ldap.schema.AttributeType;
import org.forgerock.opendj.ldap.schema.CoreSchema;
+import org.forgerock.opendj.ldap.schema.DITContentRule;
+import org.forgerock.opendj.ldap.schema.DITStructureRule;
+import org.forgerock.opendj.ldap.schema.MatchingRule;
+import org.forgerock.opendj.ldap.schema.MatchingRuleUse;
+import org.forgerock.opendj.ldap.schema.NameForm;
+import org.forgerock.opendj.ldap.schema.ObjectClass;
import org.forgerock.opendj.ldap.schema.SchemaBuilder;
+import org.forgerock.opendj.ldap.schema.SchemaBuilder.SchemaBuilderHook;
+import org.forgerock.opendj.ldap.schema.Syntax;
+import org.forgerock.opendj.ldap.schema.AttributeType.Builder;
import org.forgerock.opendj.ldif.LDIFEntryReader;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.InitializationException;
@@ -47,6 +56,7 @@
import static org.forgerock.opendj.ldap.schema.SchemaValidationPolicy.*;
import static org.opends.messages.ConfigMessages.*;
import static org.opends.server.util.StaticUtils.*;
+import static org.opends.server.util.ServerConstants.SCHEMA_PROPERTY_FILENAME;
/**
* This class defines a utility that will be used to manage the interaction with
@@ -357,7 +367,7 @@
// immediately overwrite these definitions which are already defined in the SDK core schema
final boolean overwriteCoreSchemaDefinitions =
CORE_SCHEMA_FILE.equals(schemaFile) || RFC_3112_SCHEMA_FILE.equals(schemaFile);
- updateSchema(schema, schemaEntry, overwriteCoreSchemaDefinitions);
+ updateSchema(schema, schemaFile, schemaEntry, overwriteCoreSchemaDefinitions);
}
catch (DirectoryException e)
{
@@ -369,7 +379,7 @@
logger.warn(WARN_CONFIG_CONFLICTING_DEFINITIONS_IN_SCHEMA_FILE, schemaFile, e.getMessageObject());
try
{
- updateSchema(schema, schemaEntry, true);
+ updateSchema(schema, schemaFile, schemaEntry, true);
}
catch (DirectoryException e2)
{
@@ -439,15 +449,48 @@
}
}
- private static void updateSchema(Schema schema, final Entry schemaEntry, final boolean overwrite)
- throws DirectoryException
+ private static void updateSchema(Schema schema, final String schemaFile, final Entry schemaEntry,
+ final boolean overwrite) throws DirectoryException
{
schema.updateSchema(new SchemaUpdater()
{
@Override
public org.forgerock.opendj.ldap.schema.Schema update(SchemaBuilder builder)
{
- return builder.addSchema(schemaEntry, overwrite).toSchema();
+ return builder.addSchema(schemaEntry, overwrite, new SchemaBuilderHook() {
+ @Override
+ public void beforeAddSyntax(Syntax.Builder builder) {
+ builder.extraProperties(SCHEMA_PROPERTY_FILENAME, Collections.singletonList(schemaFile));
+ }
+ @Override
+ public void beforeAddObjectClass(ObjectClass.Builder builder) {
+ builder.extraProperties(SCHEMA_PROPERTY_FILENAME, Collections.singletonList(schemaFile));
+ }
+ @Override
+ public void beforeAddNameForm(NameForm.Builder builder) {
+ builder.extraProperties(SCHEMA_PROPERTY_FILENAME, Collections.singletonList(schemaFile));
+ }
+ @Override
+ public void beforeAddMatchingRuleUse(MatchingRuleUse.Builder builder) {
+ builder.extraProperties(SCHEMA_PROPERTY_FILENAME, Collections.singletonList(schemaFile));
+ }
+ @Override
+ public void beforeAddMatchingRule(MatchingRule.Builder builder) {
+ builder.extraProperties(SCHEMA_PROPERTY_FILENAME, Collections.singletonList(schemaFile));
+ }
+ @Override
+ public void beforeAddDitStructureRule(DITStructureRule.Builder builder) {
+ builder.extraProperties(SCHEMA_PROPERTY_FILENAME, Collections.singletonList(schemaFile));
+ }
+ @Override
+ public void beforeAddDitContentRule(DITContentRule.Builder builder) {
+ builder.extraProperties(SCHEMA_PROPERTY_FILENAME, Collections.singletonList(schemaFile));
+ }
+ @Override
+ public void beforeAddAttribute(Builder builder) {
+ builder.extraProperties(SCHEMA_PROPERTY_FILENAME, Collections.singletonList(schemaFile));
+ }
+ }).toSchema();
}
});
}
--
Gitblit v1.10.0