From a6eabe64d34d4660afdf54808e95f26ac135ff6f Mon Sep 17 00:00:00 2001
From: Nicolas Capponi <nicolas.capponi@forgerock.com>
Date: Fri, 09 Sep 2016 09:45:22 +0000
Subject: [PATCH] OPENDJ-3089 Replace server schema by SDK schema in Schema Handler class
---
opendj-server-legacy/src/main/java/org/opends/server/core/SchemaHandler.java | 141 ++++++++++++++++++++++++++++++++++++++++-------
1 files changed, 120 insertions(+), 21 deletions(-)
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/core/SchemaHandler.java b/opendj-server-legacy/src/main/java/org/opends/server/core/SchemaHandler.java
index 178ea45..6c03b23 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/core/SchemaHandler.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/core/SchemaHandler.java
@@ -15,11 +15,10 @@
*/
package org.opends.server.core;
+import static org.opends.messages.SchemaMessages.ERR_SCHEMA_HAS_WARNINGS;
+
import static org.forgerock.util.Utils.*;
import static org.opends.messages.ConfigMessages.*;
-import static org.opends.server.replication.plugin.HistoricalCsnOrderingMatchingRuleImpl.*;
-import static org.opends.server.schema.AciSyntax.*;
-import static org.opends.server.schema.SubtreeSpecificationSyntax.*;
import static org.opends.server.util.StaticUtils.*;
import java.io.File;
@@ -27,14 +26,21 @@
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.List;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+import org.opends.server.replication.plugin.HistoricalCsnOrderingMatchingRuleImpl;
+import org.opends.server.schema.AciSyntax;
+import org.opends.server.schema.SubtreeSpecificationSyntax;
import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.i18n.slf4j.LocalizedLogger;
import org.forgerock.opendj.config.ClassPropertyDefinition;
import org.forgerock.opendj.config.server.ConfigException;
import org.forgerock.opendj.ldap.Entry;
+import org.forgerock.opendj.ldap.ResultCode;
import org.forgerock.opendj.ldap.schema.Schema;
import org.forgerock.opendj.ldap.schema.SchemaBuilder;
import org.forgerock.opendj.ldif.EntryReader;
@@ -42,6 +48,7 @@
import org.forgerock.opendj.server.config.meta.SchemaProviderCfgDefn;
import org.forgerock.opendj.server.config.server.RootCfg;
import org.forgerock.opendj.server.config.server.SchemaProviderCfg;
+import org.forgerock.util.Option;
import org.forgerock.util.Utils;
import org.opends.server.schema.SchemaProvider;
import org.opends.server.types.DirectoryException;
@@ -68,6 +75,16 @@
private ServerContext serverContext;
+ /**
+ * The schema.
+ * <p>
+ * @GuardedBy("exclusiveLock")
+ */
+ private volatile Schema schemaNG;
+
+ /** Guards updates to the schema. */
+ private final Lock exclusiveLock = new ReentrantLock();
+
private long oldestModificationTime = -1L;
private long youngestModificationTime = -1L;
@@ -96,9 +113,7 @@
{
this.serverContext = serverContext;
- final org.opends.server.types.Schema schema = serverContext.getSchema();
-
- schema.exclusiveLock();
+ exclusiveLock.lock();
try
{
// Start from the core schema (TODO: or start with empty schema and add core schema in core schema provider ?)
@@ -112,21 +127,12 @@
try
{
- schema.updateSchema(new SchemaUpdater()
- {
- @Override
- public Schema update(SchemaBuilder ignored)
- {
- // see RemoteSchemaLoader.readSchema()
- addAciSyntax(schemaBuilder);
- addSubtreeSpecificationSyntax(schemaBuilder);
- addHistoricalCsnOrderingMatchingRule(schemaBuilder);
+ // see RemoteSchemaLoader.readSchema()
+ AciSyntax.addAciSyntax(schemaBuilder);
+ SubtreeSpecificationSyntax.addSubtreeSpecificationSyntax(schemaBuilder);
+ HistoricalCsnOrderingMatchingRuleImpl.addHistoricalCsnOrderingMatchingRule(schemaBuilder);
- // Uses the builder incrementally updated instead of the default provided by the method.
- // This is why it is necessary to explicitly lock/unlock the schema updater.
- return schemaBuilder.toSchema();
- }
- });
+ switchSchema(schemaBuilder.toSchema());
}
catch (DirectoryException e)
{
@@ -135,11 +141,74 @@
}
finally
{
- schema.exclusiveUnlock();
+ exclusiveLock.unlock();
}
}
/**
+ * Update the schema using the provided schema updater.
+ * <p>
+ * An implicit lock is performed, so it is in general not necessary
+ * to call the {code lock()} and {code unlock() methods.
+ * However, these method should be used if/when the SchemaBuilder passed
+ * as an argument to the updater is not used to return the schema
+ * (see for example usage in {@code CoreSchemaProvider} class). This
+ * case should remain exceptional.
+ *
+ * @param updater
+ * the updater that returns a new schema
+ * @throws DirectoryException if there is any problem updating the schema
+ */
+ public void updateSchema(SchemaUpdater updater) throws DirectoryException
+ {
+ exclusiveLock.lock();
+ try
+ {
+ switchSchema(updater.update(new SchemaBuilder(schemaNG)));
+ }
+ finally
+ {
+ exclusiveLock.unlock();
+ }
+ }
+
+ /**
+ * Updates the schema option if the new value differs from the old value.
+ *
+ * @param <T> the schema option's type
+ * @param option the schema option to update
+ * @param newValue the new value for the schema option
+ * @throws DirectoryException if there is any problem updating the schema
+ */
+ public <T> void updateSchemaOption(final Option<T> option, final T newValue) throws DirectoryException
+ {
+ final T oldValue = schemaNG.getOption(option);
+ if (!oldValue.equals(newValue))
+ {
+ updateSchema(new SchemaUpdater()
+ {
+ @Override
+ public Schema update(SchemaBuilder builder)
+ {
+ return builder.setOption(option, newValue).toSchema();
+ }
+ });
+ }
+ }
+
+ /** Takes an exclusive lock on the schema. */
+ public void exclusiveLock()
+ {
+ exclusiveLock.lock();
+ }
+
+ /** Releases an exclusive lock on the schema. */
+ public void exclusiveUnlock()
+ {
+ exclusiveLock.unlock();
+ }
+
+ /**
* Load the schema from provided root configuration.
*
* @param rootConfiguration
@@ -382,6 +451,23 @@
}
}
+ private void switchSchema(Schema newSchema) throws DirectoryException
+ {
+ rejectSchemaWithWarnings(newSchema);
+ schemaNG = newSchema.asNonStrictSchema();
+ Schema.setDefaultSchema(schemaNG);
+ }
+
+ private void rejectSchemaWithWarnings(Schema newSchema) throws DirectoryException
+ {
+ Collection<LocalizableMessage> warnings = newSchema.getWarnings();
+ if (!warnings.isEmpty())
+ {
+ throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION,
+ ERR_SCHEMA_HAS_WARNINGS.get(warnings.size(), Utils.joinAsString("; ", warnings)));
+ }
+ }
+
/** A file filter implementation that accepts only LDIF files. */
private static class SchemaFileFilter implements FilenameFilter
{
@@ -393,4 +479,17 @@
return filename.endsWith(LDIF_SUFFIX);
}
}
+
+ /** Interface to update a schema provided a schema builder. */
+ public interface SchemaUpdater
+ {
+ /**
+ * Returns an updated schema.
+ *
+ * @param builder
+ * The builder on the current schema
+ * @return the new schema
+ */
+ Schema update(SchemaBuilder builder);
+ }
}
--
Gitblit v1.10.0