From 54f8773ef2d74f398f3d77f66f708a3d7a5e6855 Mon Sep 17 00:00:00 2001
From: matthew_swift <matthew_swift@localhost>
Date: Tue, 17 Jul 2007 09:44:09 +0000
Subject: [PATCH] Fix issue 1793: server side notification of changes to inherited defaults
---
opends/src/server/org/opends/server/admin/server/ConfigChangeListenerAdaptor.java | 302 +++++++++++++++++++++++-
opends/src/server/org/opends/server/admin/server/ServerManagedObject.java | 36 ++
opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/DefaultBehaviorTest.java | 4
opends/src/server/org/opends/server/admin/server/ConfigAddListenerAdaptor.java | 2
opends/src/server/org/opends/server/admin/server/DependencyConfigChangeListener.java | 153 ++++++++++++
opends/src/server/org/opends/server/admin/server/CleanerConfigDeleteListener.java | 172 ++++++++++++++
6 files changed, 647 insertions(+), 22 deletions(-)
diff --git a/opends/src/server/org/opends/server/admin/server/CleanerConfigDeleteListener.java b/opends/src/server/org/opends/server/admin/server/CleanerConfigDeleteListener.java
new file mode 100644
index 0000000..dd5c7b3
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/server/CleanerConfigDeleteListener.java
@@ -0,0 +1,172 @@
+/*
+ * 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.admin.server;
+
+
+
+import static org.opends.server.loggers.ErrorLogger.*;
+import static org.opends.server.loggers.debug.DebugLogger.*;
+import static org.opends.server.messages.MessageHandler.*;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.opends.server.api.ConfigChangeListener;
+import org.opends.server.api.ConfigDeleteListener;
+import org.opends.server.config.ConfigEntry;
+import org.opends.server.config.ConfigException;
+import org.opends.server.core.DirectoryServer;
+import org.opends.server.loggers.debug.DebugTracer;
+import org.opends.server.messages.AdminMessages;
+import org.opends.server.types.ConfigChangeResult;
+import org.opends.server.types.DN;
+import org.opends.server.types.DebugLogLevel;
+import org.opends.server.types.ErrorLogCategory;
+import org.opends.server.types.ErrorLogSeverity;
+import org.opends.server.types.ResultCode;
+import org.opends.server.util.StaticUtils;
+
+
+
+/**
+ * A configuration delete listener which detects when a specified
+ * entry is removed and, when it is, cleans up any listeners
+ * associated with it.
+ */
+final class CleanerConfigDeleteListener implements ConfigDeleteListener {
+
+ /**
+ * The tracer object for the debug logger.
+ */
+ private static final DebugTracer TRACER = getTracer();
+
+ // The change listeners.
+ private Map<DN, ConfigChangeListener> changeListeners =
+ new HashMap<DN, ConfigChangeListener>();
+
+ // The DN of the monitored configuration entry.
+ private final DN dn;
+
+
+
+ /**
+ * Creates a new cleaner configuration change listener which will
+ * remove any registered listeners when then configuration entry it
+ * is monitoring is removed.
+ *
+ * @param dn
+ * The DN of the entry to be monitored.
+ */
+ public CleanerConfigDeleteListener(DN dn) {
+ this.dn = dn;
+ }
+
+
+
+ /**
+ * Register a configuration change listener for removal when the
+ * monitored entry is removed.
+ *
+ * @param dn
+ * The name of the entry associated with the configuration
+ * change listener.
+ * @param listener
+ * The configuration change listener.
+ */
+ public void addConfigChangeListener(DN dn, ConfigChangeListener listener) {
+ changeListeners.put(dn, listener);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public ConfigChangeResult applyConfigurationDelete(ConfigEntry configEntry) {
+ // Remove the listeners if the deleted entry is the monitored
+ // entry.
+ if (configEntry.getDN().equals(dn)) {
+ for (Map.Entry<DN, ConfigChangeListener> me :
+ changeListeners.entrySet()) {
+ ConfigEntry listenerConfigEntry = getConfigEntry(me.getKey());
+ if (listenerConfigEntry != null) {
+ listenerConfigEntry.deregisterChangeListener(me.getValue());
+ }
+ }
+
+ // Now remove this listener as we are no longer needed.
+ ConfigEntry parentConfigEntry = getConfigEntry(dn.getParent());
+ if (parentConfigEntry != null) {
+ parentConfigEntry.deregisterDeleteListener(this);
+ }
+ }
+
+ return new ConfigChangeResult(ResultCode.SUCCESS, false);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean configDeleteIsAcceptable(ConfigEntry configEntry,
+ StringBuilder unacceptableReason) {
+ // Always acceptable.
+ return true;
+ }
+
+
+
+ // Returns the named configuration entry or null if it could not be
+ // retrieved.
+ private ConfigEntry getConfigEntry(DN dn) {
+ try {
+ ConfigEntry configEntry = DirectoryServer.getConfigEntry(dn);
+ if (configEntry != null) {
+ return configEntry;
+ } else {
+ int msgID = AdminMessages.MSGID_ADMIN_MANAGED_OBJECT_DOES_NOT_EXIST;
+ String message = getMessage(msgID, String.valueOf(dn));
+ logError(ErrorLogCategory.CONFIGURATION, ErrorLogSeverity.MILD_ERROR,
+ message, msgID);
+ }
+ } catch (ConfigException e) {
+ // The dependent entry could not be retrieved.
+ if (debugEnabled()) {
+ TRACER.debugCaught(DebugLogLevel.ERROR, e);
+ }
+
+ int msgID = AdminMessages.MSGID_ADMIN_CANNOT_GET_MANAGED_OBJECT;
+ String message = getMessage(msgID, String.valueOf(dn), StaticUtils
+ .getExceptionMessage(e));
+ logError(ErrorLogCategory.CONFIGURATION, ErrorLogSeverity.MILD_ERROR,
+ message, msgID);
+ }
+
+ return null;
+ }
+}
diff --git a/opends/src/server/org/opends/server/admin/server/ConfigAddListenerAdaptor.java b/opends/src/server/org/opends/server/admin/server/ConfigAddListenerAdaptor.java
index 8d55359..d4d3c33 100644
--- a/opends/src/server/org/opends/server/admin/server/ConfigAddListenerAdaptor.java
+++ b/opends/src/server/org/opends/server/admin/server/ConfigAddListenerAdaptor.java
@@ -175,7 +175,7 @@
ServerManagedObject<? extends S> mo;
try {
mo = ServerManagedObject.decode(childPath, r
- .getChildDefinition(), configEntry);
+ .getChildDefinition(), configEntry, configEntry);
} catch (DecodingException e) {
generateUnacceptableReason(e, unacceptableReason);
return false;
diff --git a/opends/src/server/org/opends/server/admin/server/ConfigChangeListenerAdaptor.java b/opends/src/server/org/opends/server/admin/server/ConfigChangeListenerAdaptor.java
index 439c308..58ae50a 100644
--- a/opends/src/server/org/opends/server/admin/server/ConfigChangeListenerAdaptor.java
+++ b/opends/src/server/org/opends/server/admin/server/ConfigChangeListenerAdaptor.java
@@ -28,43 +28,194 @@
+import static org.opends.server.loggers.ErrorLogger.*;
+import static org.opends.server.loggers.debug.DebugLogger.*;
+import static org.opends.server.messages.MessageHandler.*;
+
+import java.util.Collection;
+import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
+import java.util.Set;
+import org.opends.server.admin.AbsoluteInheritedDefaultBehaviorProvider;
import org.opends.server.admin.AbstractManagedObjectDefinition;
+import org.opends.server.admin.AliasDefaultBehaviorProvider;
import org.opends.server.admin.Configuration;
import org.opends.server.admin.DecodingException;
+import org.opends.server.admin.DefaultBehaviorProvider;
+import org.opends.server.admin.DefaultBehaviorProviderVisitor;
+import org.opends.server.admin.DefinedDefaultBehaviorProvider;
import org.opends.server.admin.ManagedObjectPath;
+import org.opends.server.admin.PropertyDefinition;
+import org.opends.server.admin.RelativeInheritedDefaultBehaviorProvider;
+import org.opends.server.admin.UndefinedDefaultBehaviorProvider;
import org.opends.server.api.ConfigChangeListener;
import org.opends.server.config.ConfigEntry;
+import org.opends.server.config.ConfigException;
+import org.opends.server.core.DirectoryServer;
+import org.opends.server.loggers.debug.DebugTracer;
+import org.opends.server.messages.AdminMessages;
import org.opends.server.types.ConfigChangeResult;
+import org.opends.server.types.DN;
+import org.opends.server.types.DebugLogLevel;
+import org.opends.server.types.ErrorLogCategory;
+import org.opends.server.types.ErrorLogSeverity;
+import org.opends.server.util.StaticUtils;
/**
* An adaptor class which converts {@link ConfigChangeListener}
- * callbacks to strongly typed {@link ConfigurationChangeListener}
- * callbacks.
+ * call-backs to strongly typed {@link ConfigurationChangeListener}
+ * call-backs.
*
* @param <S>
* The type of server configuration handled by the change
* listener.
*/
-final class ConfigChangeListenerAdaptor<S extends Configuration>
- extends AbstractConfigListenerAdaptor implements
- ConfigChangeListener {
+final class ConfigChangeListenerAdaptor<S extends Configuration> extends
+ AbstractConfigListenerAdaptor implements ConfigChangeListener {
- // The managed object path.
- private final ManagedObjectPath path;
+ /**
+ * A default behavior visitor used for determining the set of
+ * dependencies.
+ *
+ * @param <T>
+ * The type of property.
+ */
+ private static final class Visitor<T> implements
+ DefaultBehaviorProviderVisitor<T, Void, ManagedObjectPath> {
+
+ /**
+ * Finds the dependencies associated with the provided property
+ * definition.
+ *
+ * @param <T>
+ * @param path
+ * The current base path used for relative name
+ * resolution.
+ * @param pd
+ * The property definition.
+ * @param dependencies
+ * Add dependencies names to this collection.
+ */
+ public static <T> void find(ManagedObjectPath path,
+ PropertyDefinition<T> pd, Collection<DN> dependencies) {
+ Visitor<T> v = new Visitor<T>(dependencies);
+ DefaultBehaviorProvider<T> db = pd.getDefaultBehaviorProvider();
+ db.accept(v, path);
+ }
+
+ // The names of entries that this change listener depends on.
+ private final Collection<DN> dependencies;
+
+
+
+ // Prevent instantiation.
+ private Visitor(Collection<DN> dependencies) {
+ this.dependencies = dependencies;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public Void visitAbsoluteInherited(
+ AbsoluteInheritedDefaultBehaviorProvider<T> d, ManagedObjectPath p) {
+ ManagedObjectPath next = d.getManagedObjectPath();
+ dependencies.add(DNBuilder.create(next));
+
+ // If the dependent property uses inherited defaults then
+ // recursively get those as well.
+ String propertyName = d.getPropertyName();
+ AbstractManagedObjectDefinition<?, ?> mod = d
+ .getManagedObjectDefinition();
+ PropertyDefinition<?> pd = mod.getPropertyDefinition(propertyName);
+ find(next, pd, dependencies);
+
+ return null;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public Void visitAlias(AliasDefaultBehaviorProvider<T> d,
+ ManagedObjectPath p) {
+ return null;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public Void visitDefined(DefinedDefaultBehaviorProvider<T> d,
+ ManagedObjectPath p) {
+ return null;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public Void visitRelativeInherited(
+ RelativeInheritedDefaultBehaviorProvider<T> d, ManagedObjectPath p) {
+ ManagedObjectPath next = d.getManagedObjectPath(p);
+ dependencies.add(DNBuilder.create(next));
+
+ // If the dependent property uses inherited defaults then
+ // recursively get those as well.
+ String propertyName = d.getPropertyName();
+ AbstractManagedObjectDefinition<?, ?> mod = d
+ .getManagedObjectDefinition();
+ PropertyDefinition<?> pd = mod.getPropertyDefinition(propertyName);
+ find(next, pd, dependencies);
+
+ return null;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public Void visitUndefined(UndefinedDefaultBehaviorProvider<T> d,
+ ManagedObjectPath p) {
+ return null;
+ }
+ }
+
+ /**
+ * The tracer object for the debug logger.
+ */
+ private static final DebugTracer TRACER = getTracer();
+
+ // Cached managed object between accept/apply call-backs.
+ private ServerManagedObject<? extends S> cachedManagedObject;
// The managed object definition.
private final AbstractManagedObjectDefinition<?, S> d;
+ // The names of entries that this change listener depends on.
+ private final Set<DN> dependencies;
+
+ // The listener used to notify this listener when dependency entries
+ // are modified.
+ private final DependencyConfigChangeListener dependencyListener;
+
+ // The DN associated with this listener.
+ private final DN dn;
+
// The underlying change listener.
private final ConfigurationChangeListener<? super S> listener;
- // Cached managed object between accept/apply callbacks.
- private ServerManagedObject<? extends S> cachedManagedObject;
+ // The managed object path.
+ private final ManagedObjectPath path;
@@ -82,9 +233,47 @@
AbstractManagedObjectDefinition<?, S> d,
ConfigurationChangeListener<? super S> listener) {
this.path = path;
+ this.dn = DNBuilder.create(path);
this.d = d;
this.listener = listener;
this.cachedManagedObject = null;
+
+ // This change listener should be notified when dependent entries
+ // are modified. Determine the dependencies and register change
+ // listeners against them.
+ this.dependencies = new HashSet<DN>();
+ this.dependencyListener = new DependencyConfigChangeListener(dn, this);
+
+ for (PropertyDefinition<?> pd : d.getAllPropertyDefinitions()) {
+ Visitor.find(path, pd, dependencies);
+ }
+
+ CleanerConfigDeleteListener cleaner = new CleanerConfigDeleteListener(dn);
+ for (DN entryDN : dependencies) {
+ // Be careful not to register listeners against the dependent
+ // entry itself.
+ if (!entryDN.equals(dn)) {
+ ConfigEntry configEntry = getConfigEntry(entryDN);
+ if (configEntry != null) {
+ configEntry.registerChangeListener(dependencyListener);
+ cleaner.addConfigChangeListener(entryDN, dependencyListener);
+ }
+ }
+ }
+
+ // Register a delete listener which will remove the dependency
+ // listeners when this entry is removed.
+
+ // FIXME: we should really remove the dependency listeners when
+ // this listener is deregistered, but we have no way to track
+ // that.
+ DN parent = dn.getParent();
+ if (parent != null) {
+ ConfigEntry configEntry = getConfigEntry(dn.getParent());
+ if (configEntry != null) {
+ configEntry.registerDeleteListener(cleaner);
+ }
+ }
}
@@ -92,13 +281,33 @@
/**
* {@inheritDoc}
*/
- public ConfigChangeResult applyConfigurationChange(
- ConfigEntry configEntry) {
+ public ConfigChangeResult applyConfigurationChange(ConfigEntry configEntry) {
+ return applyConfigurationChange(configEntry, configEntry);
+ }
+
+
+
+ /**
+ * Attempts to apply a new configuration to this Directory Server
+ * component based on the provided changed entry.
+ *
+ * @param configEntry
+ * The configuration entry that containing the updated
+ * configuration for this component.
+ * @param newConfigEntry
+ * The configuration entry that caused the notification
+ * (will be different from <code>configEntry</code> if a
+ * dependency was modified).
+ * @return Information about the result of processing the
+ * configuration change.
+ */
+ public ConfigChangeResult applyConfigurationChange(ConfigEntry configEntry,
+ ConfigEntry newConfigEntry) {
// TODO: looking at the ConfigFileHandler implementation reveals
// that this ConfigEntry will actually be a different object to
- // the one passed in the previous callback (it will have the same
- // content though). This config entry has the correct listener
- // lists.
+ // the one passed in the previous call-back (it will have the same
+ // content though). This configuration entry has the correct
+ // listener lists.
cachedManagedObject.setConfigEntry(configEntry);
return listener.applyConfigurationChange(cachedManagedObject
@@ -112,9 +321,36 @@
*/
public boolean configChangeIsAcceptable(ConfigEntry configEntry,
StringBuilder unacceptableReason) {
+ return configChangeIsAcceptable(configEntry, unacceptableReason,
+ configEntry);
+ }
+
+
+
+ /**
+ * Indicates whether the configuration entry that will result from a
+ * proposed modification is acceptable to this change listener.
+ *
+ * @param configEntry
+ * The configuration entry that will result from the
+ * requested update.
+ * @param unacceptableReason
+ * A buffer to which this method can append a
+ * human-readable message explaining why the proposed
+ * change is not acceptable.
+ * @param newConfigEntry
+ * The configuration entry that caused the notification
+ * (will be different from <code>configEntry</code> if a
+ * dependency was modified).
+ * @return <CODE>true</CODE> if the proposed entry contains an
+ * acceptable configuration, or <CODE>false</CODE> if it
+ * does not.
+ */
+ public boolean configChangeIsAcceptable(ConfigEntry configEntry,
+ StringBuilder unacceptableReason, ConfigEntry newConfigEntry) {
try {
- cachedManagedObject = ServerManagedObject.decode(path, d,
- configEntry);
+ cachedManagedObject = ServerManagedObject.decode(path, d, configEntry,
+ newConfigEntry);
} catch (DecodingException e) {
generateUnacceptableReason(e, unacceptableReason);
return false;
@@ -133,7 +369,7 @@
/**
- * Get the configuiration change listener associated with this
+ * Get the configuration change listener associated with this
* adaptor.
*
* @return Returns the configuration change listener associated with
@@ -142,4 +378,36 @@
ConfigurationChangeListener<? super S> getConfigurationChangeListener() {
return listener;
}
+
+
+
+ // Returns the named configuration entry or null if it could not be
+ // retrieved.
+ private ConfigEntry getConfigEntry(DN dn) {
+ try {
+ ConfigEntry configEntry = DirectoryServer.getConfigEntry(dn);
+ if (configEntry != null) {
+ return configEntry;
+ } else {
+ int msgID = AdminMessages.MSGID_ADMIN_MANAGED_OBJECT_DOES_NOT_EXIST;
+ String message = getMessage(msgID, String.valueOf(dn));
+ logError(ErrorLogCategory.CONFIGURATION, ErrorLogSeverity.SEVERE_ERROR,
+ message, msgID);
+ }
+ } catch (ConfigException e) {
+ // The dependent entry could not be retrieved.
+ if (debugEnabled()) {
+ TRACER.debugCaught(DebugLogLevel.ERROR, e);
+ }
+
+ int msgID = AdminMessages.MSGID_ADMIN_CANNOT_GET_MANAGED_OBJECT;
+ String message = getMessage(msgID, String.valueOf(dn), StaticUtils
+ .getExceptionMessage(e));
+ logError(ErrorLogCategory.CONFIGURATION, ErrorLogSeverity.SEVERE_ERROR,
+ message, msgID);
+ }
+
+ return null;
+ }
+
}
diff --git a/opends/src/server/org/opends/server/admin/server/DependencyConfigChangeListener.java b/opends/src/server/org/opends/server/admin/server/DependencyConfigChangeListener.java
new file mode 100644
index 0000000..c3ed339
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/server/DependencyConfigChangeListener.java
@@ -0,0 +1,153 @@
+/*
+ * 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.admin.server;
+
+
+
+import static org.opends.server.loggers.ErrorLogger.*;
+import static org.opends.server.loggers.debug.DebugLogger.*;
+import static org.opends.server.messages.MessageHandler.*;
+
+import org.opends.server.api.ConfigChangeListener;
+import org.opends.server.config.ConfigEntry;
+import org.opends.server.config.ConfigException;
+import org.opends.server.core.DirectoryServer;
+import org.opends.server.loggers.debug.DebugTracer;
+import org.opends.server.messages.AdminMessages;
+import org.opends.server.types.ConfigChangeResult;
+import org.opends.server.types.DN;
+import org.opends.server.types.DebugLogLevel;
+import org.opends.server.types.ErrorLogCategory;
+import org.opends.server.types.ErrorLogSeverity;
+import org.opends.server.types.ResultCode;
+import org.opends.server.util.StaticUtils;
+
+
+
+/**
+ * A configuration change listener which can be used to notify a
+ * change listener when modifications are made to configuration
+ * entries that it depends upon.
+ */
+final class DependencyConfigChangeListener implements ConfigChangeListener {
+
+ /**
+ * The tracer object for the debug logger.
+ */
+ private static final DebugTracer TRACER = getTracer();
+
+ // The DN of the dependent configuration entry.
+ private final DN dependentDN;
+
+ // The dependent configuration change listener adaptor.
+ private final ConfigChangeListenerAdaptor<?> dependentListener;
+
+
+
+ /**
+ * Creates a new dependency configuration change listener which will
+ * notify the dependent listener whenever the configuration entry
+ * that this listener monitors is modified.
+ *
+ * @param dependentDN
+ * The DN of the dependent configuration entry.
+ * @param dependentListener
+ * The dependent configuration change listener adaptor.
+ */
+ public DependencyConfigChangeListener(DN dependentDN,
+ ConfigChangeListenerAdaptor<?> dependentListener) {
+ this.dependentDN = dependentDN;
+ this.dependentListener = dependentListener;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public ConfigChangeResult applyConfigurationChange(ConfigEntry configEntry) {
+ ConfigEntry dependentConfigEntry = getConfigEntry(dependentDN);
+ if (dependentConfigEntry != null) {
+ return dependentListener.applyConfigurationChange(dependentConfigEntry,
+ configEntry);
+ } else {
+ // The dependent entry was not found.
+ configEntry.deregisterChangeListener(this);
+ return new ConfigChangeResult(ResultCode.SUCCESS, false);
+ }
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean configChangeIsAcceptable(ConfigEntry configEntry,
+ StringBuilder unacceptableReason) {
+ ConfigEntry dependentConfigEntry = getConfigEntry(dependentDN);
+ if (dependentConfigEntry != null) {
+ return dependentListener.configChangeIsAcceptable(dependentConfigEntry,
+ unacceptableReason, configEntry);
+ } else {
+ // The dependent entry was not found.
+ configEntry.deregisterChangeListener(this);
+ return true;
+ }
+ }
+
+
+
+ // Returns the named configuration entry or null if it could not be
+ // retrieved.
+ private ConfigEntry getConfigEntry(DN dn) {
+ try {
+ ConfigEntry configEntry = DirectoryServer.getConfigEntry(dn);
+ if (configEntry != null) {
+ return configEntry;
+ } else {
+ int msgID = AdminMessages.MSGID_ADMIN_MANAGED_OBJECT_DOES_NOT_EXIST;
+ String message = getMessage(msgID, String.valueOf(dn));
+ logError(ErrorLogCategory.CONFIGURATION, ErrorLogSeverity.MILD_ERROR,
+ message, msgID);
+ }
+ } catch (ConfigException e) {
+ // The dependent entry could not be retrieved.
+ if (debugEnabled()) {
+ TRACER.debugCaught(DebugLogLevel.ERROR, e);
+ }
+
+ int msgID = AdminMessages.MSGID_ADMIN_CANNOT_GET_MANAGED_OBJECT;
+ String message = getMessage(msgID, String.valueOf(dn), StaticUtils
+ .getExceptionMessage(e));
+ logError(ErrorLogCategory.CONFIGURATION, ErrorLogSeverity.MILD_ERROR,
+ message, msgID);
+ }
+
+ return null;
+ }
+
+}
diff --git a/opends/src/server/org/opends/server/admin/server/ServerManagedObject.java b/opends/src/server/org/opends/server/admin/server/ServerManagedObject.java
index b2792fe..ed9e19a 100644
--- a/opends/src/server/org/opends/server/admin/server/ServerManagedObject.java
+++ b/opends/src/server/org/opends/server/admin/server/ServerManagedObject.java
@@ -396,6 +396,40 @@
ManagedObjectPath path, AbstractManagedObjectDefinition<?, S> definition,
ConfigEntry configEntry) throws DefinitionDecodingException,
ServerManagedObjectDecodingException {
+ return decode(path, definition, configEntry, null);
+ }
+
+
+
+ /**
+ * Decodes a configuration entry into the required type of server
+ * managed object.
+ *
+ * @param <S>
+ * The type of server configuration represented by the
+ * decoded server managed object.
+ * @param path
+ * The location of the server managed object.
+ * @param definition
+ * The required managed object type.
+ * @param configEntry
+ * The configuration entry that should be decoded.
+ * @param newConfigEntry
+ * Optional new configuration that does not exist yet in
+ * the configuration back-end. This will be used for
+ * resolving inherited default values.
+ * @return Returns the new server-side managed object from the
+ * provided definition and configuration entry.
+ * @throws DefinitionDecodingException
+ * If the managed object's type could not be determined.
+ * @throws ServerManagedObjectDecodingException
+ * If one or more of the managed object's properties could
+ * not be decoded.
+ */
+ static <S extends Configuration> ServerManagedObject<? extends S> decode(
+ ManagedObjectPath path, AbstractManagedObjectDefinition<?, S> definition,
+ ConfigEntry configEntry, ConfigEntry newConfigEntry)
+ throws DefinitionDecodingException, ServerManagedObjectDecodingException {
// First determine the correct definition to use for the entry.
// This could either be the provided definition, or one of its
// sub-definitions.
@@ -410,7 +444,7 @@
for (PropertyDefinition<?> pd : mod.getAllPropertyDefinitions()) {
List<String> values = getAttribute(mod, pd, configEntry);
try {
- decodeProperty(properties, path, pd, values, configEntry);
+ decodeProperty(properties, path, pd, values, newConfigEntry);
} catch (PropertyException e) {
exceptions.add(e);
}
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/DefaultBehaviorTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/DefaultBehaviorTest.java
index 5d850e4..b1ff264 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/DefaultBehaviorTest.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/DefaultBehaviorTest.java
@@ -581,13 +581,11 @@
* change listener. This test makes sure that a component is
* notified when the default values it inherits from another
* component are modified.
- * <p>
- * FIXME: disabled - waiting for fix to issue 1793.
*
* @throws Exception
* If the test unexpectedly fails.
*/
- @Test(enabled = false)
+ @Test
public void testChangeListenerChildValues4() throws Exception {
TestParentCfg parent = getParent("test parent 1");
--
Gitblit v1.10.0