From 3f6373b52c42fd596d3659d335542909cfdd5fbb Mon Sep 17 00:00:00 2001
From: Nicolas Capponi <nicolas.capponi@forgerock.com>
Date: Fri, 20 Dec 2013 14:37:56 +0000
Subject: [PATCH] Checkpoint commit for OPENDJ-1235 : Migrate configuration framework
---
opendj-sdk/opendj-admin/src/main/java/org/opends/server/admin/server/ConfigAddListenerAdaptor.java | 369 ++--
opendj-sdk/opendj-admin/src/test/java/org/opends/server/admin/server/AdminTestCaseUtils.java | 117 +
opendj-sdk/opendj-admin/src/test/java/org/opends/server/admin/server/AggregationServerTest.java | 814 +++++++++++
opendj-sdk/opendj-admin/src/main/java/org/opends/server/core/DirectoryServer.java | 7
opendj-sdk/opendj-admin/src/main/java/org/opends/server/admin/server/ConfigDeleteListenerAdaptor.java | 37
opendj-sdk/opendj-admin/src/main/java/org/opends/server/admin/server/ServerManagementContext.java | 137 +
opendj-sdk/opendj-admin/src/main/java/org/opends/server/admin/server/ConfigChangeListenerAdaptor.java | 99
opendj-sdk/opendj-admin/src/main/java/org/opends/server/admin/server/AbstractConfigListenerAdaptor.java | 58
opendj-sdk/opendj-admin/src/main/java/org/opends/server/admin/server/DelayedConfigAddListener.java | 31
opendj-sdk/opendj-admin/src/test/java/org/opends/server/admin/server/ListenerTest.java | 275 +++
/dev/null | 234 ---
opendj-sdk/opendj-admin/src/main/java/org/opends/server/admin/AggregationPropertyDefinition.java | 6
opendj-sdk/opendj-admin/src/main/java/org/opends/server/api/ConfigDeleteListener.java | 69
opendj-sdk/opendj-admin/src/test/java/org/opends/server/admin/server/DNBuilderTest.java | 165 ++
opendj-sdk/opendj-admin/src/test/java/org/opends/server/admin/server/DefaultBehaviorTest.java | 711 ++++++++++
opendj-sdk/opendj-admin/src/test/java/org/opends/server/admin/server/ConstraintTest.java | 489 ++++++
opendj-sdk/opendj-admin/src/main/java/org/opends/server/api/ConfigChangeListener.java | 6
opendj-sdk/opendj-admin/src/main/java/org/opends/server/admin/server/ServerManagedObject.java | 316 ++--
opendj-sdk/opendj-admin/src/main/java/org/opends/server/config/ConfigurationRepository.java | 146 +
opendj-sdk/opendj-admin/src/main/java/org/opends/server/api/ConfigAddListener.java | 6
opendj-sdk/opendj-admin/src/test/java/org/opends/server/admin/server/MockConstraint.java | 146 ++
21 files changed, 3,441 insertions(+), 797 deletions(-)
diff --git a/opendj-sdk/opendj-admin/src/main/java/org/opends/server/admin/AggregationPropertyDefinition.java b/opendj-sdk/opendj-admin/src/main/java/org/opends/server/admin/AggregationPropertyDefinition.java
index 29e126b..56c4ef1 100644
--- a/opendj-sdk/opendj-admin/src/main/java/org/opends/server/admin/AggregationPropertyDefinition.java
+++ b/opendj-sdk/opendj-admin/src/main/java/org/opends/server/admin/AggregationPropertyDefinition.java
@@ -348,7 +348,7 @@
public boolean isUsable(ServerManagedObject<?> managedObject, Collection<LocalizableMessage> unacceptableReasons)
throws ConfigException {
SortedSet<String> names = managedObject.getPropertyValues(AggregationPropertyDefinition.this);
- ServerManagementContext context = ServerManagementContext.getInstance();
+ ServerManagementContext context = managedObject.getServerContext();
LocalizableMessage thisUFN = managedObject.getManagedObjectDefinition().getUserFriendlyName();
String thisDN = managedObject.getDN().toString();
LocalizableMessage thatUFN = getRelationDefinition().getUserFriendlyName();
@@ -404,7 +404,7 @@
// Delete listeners need to be registered against the parent
// entry of the referenced components.
- ServerManagementContext context = ServerManagementContext.getInstance();
+ ServerManagementContext context = managedObject.getServerContext();
ManagedObjectPath<?, ?> parentPath = getParentPath();
ServerManagedObject<?> parent = context.getManagedObject(parentPath);
@@ -443,7 +443,7 @@
@Override
public void performPostDelete(ServerManagedObject<?> managedObject) throws ConfigException {
// Remove any registered delete and change listeners.
- ServerManagementContext context = ServerManagementContext.getInstance();
+ ServerManagementContext context = managedObject.getServerContext();
DN dn = managedObject.getDN();
// Delete listeners need to be deregistered against the parent
diff --git a/opendj-sdk/opendj-admin/src/main/java/org/opends/server/admin/server/AbstractConfigListenerAdaptor.java b/opendj-sdk/opendj-admin/src/main/java/org/opends/server/admin/server/AbstractConfigListenerAdaptor.java
index 596ef26..e1c7f7a 100644
--- a/opendj-sdk/opendj-admin/src/main/java/org/opends/server/admin/server/AbstractConfigListenerAdaptor.java
+++ b/opendj-sdk/opendj-admin/src/main/java/org/opends/server/admin/server/AbstractConfigListenerAdaptor.java
@@ -25,47 +25,41 @@
*/
package org.opends.server.admin.server;
-
-
import java.util.Collection;
import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.i18n.LocalizableMessageBuilder;
-
-
/**
* Common features of config listener adaptors.
*/
abstract class AbstractConfigListenerAdaptor {
- /**
- * Create a new config listener adaptor.
- */
- protected AbstractConfigListenerAdaptor() {
- // No implementation required.
- }
-
-
-
- /**
- * Concatenate a list of messages into a single message.
- *
- * @param reasons
- * The list of messages to concatenate.
- * @param unacceptableReason
- * The single message to which messages should be appended.
- */
- protected final void generateUnacceptableReason(Collection<LocalizableMessage> reasons,
- LocalizableMessageBuilder unacceptableReason) {
- boolean isFirst = true;
- for (LocalizableMessage reason : reasons) {
- if (isFirst) {
- isFirst = false;
- } else {
- unacceptableReason.append(" ");
- }
- unacceptableReason.append(reason);
+ /**
+ * Create a new config listener adaptor.
+ */
+ protected AbstractConfigListenerAdaptor() {
+ // No implementation required.
}
- }
+
+ /**
+ * Concatenate a list of messages into a single message.
+ *
+ * @param reasons
+ * The list of messages to concatenate.
+ * @param unacceptableReason
+ * The single message to which messages should be appended.
+ */
+ protected final void generateUnacceptableReason(Collection<LocalizableMessage> reasons,
+ LocalizableMessageBuilder unacceptableReason) {
+ boolean isFirst = true;
+ for (LocalizableMessage reason : reasons) {
+ if (isFirst) {
+ isFirst = false;
+ } else {
+ unacceptableReason.append(" ");
+ }
+ unacceptableReason.append(reason);
+ }
+ }
}
diff --git a/opendj-sdk/opendj-admin/src/main/java/org/opends/server/admin/server/ConfigAddListenerAdaptor.java b/opendj-sdk/opendj-admin/src/main/java/org/opends/server/admin/server/ConfigAddListenerAdaptor.java
index b6b5bea..8976ef1 100644
--- a/opendj-sdk/opendj-admin/src/main/java/org/opends/server/admin/server/ConfigAddListenerAdaptor.java
+++ b/opendj-sdk/opendj-admin/src/main/java/org/opends/server/admin/server/ConfigAddListenerAdaptor.java
@@ -25,8 +25,6 @@
*/
package org.opends.server.admin.server;
-
-
import java.util.LinkedList;
import java.util.List;
@@ -43,229 +41,214 @@
import org.opends.server.admin.SetRelationDefinition;
import org.opends.server.admin.DefinitionDecodingException.Reason;
import org.opends.server.api.ConfigAddListener;
-import org.opends.server.config.ConfigEntry;
import org.opends.server.config.ConfigException;
import org.opends.server.types.ConfigChangeResult;
import org.forgerock.opendj.ldap.DN;
+import org.forgerock.opendj.ldap.Entry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.forgerock.opendj.ldap.ResultCode;
-
-
/**
- * An adaptor class which converts {@link ConfigAddListener} callbacks
- * to {@link ServerManagedObjectAddListener} callbacks.
+ * An adaptor class which converts {@link ConfigAddListener} callbacks to
+ * {@link ServerManagedObjectAddListener} callbacks.
*
* @param <S>
- * The type of server configuration handled by the add
- * listener.
+ * The type of server configuration handled by the add listener.
*/
-final class ConfigAddListenerAdaptor<S extends Configuration> extends
- AbstractConfigListenerAdaptor implements ConfigAddListener {
+final class ConfigAddListenerAdaptor<S extends Configuration> extends AbstractConfigListenerAdaptor implements
+ ConfigAddListener {
- private static final Logger debugLogger = LoggerFactory.getLogger(ConfigAddListenerAdaptor.class);
+ private static final Logger debugLogger = LoggerFactory.getLogger(ConfigAddListenerAdaptor.class);
- // Cached managed object between accept/apply callbacks.
- private ServerManagedObject<? extends S> cachedManagedObject;
+ // Cached managed object between accept/apply callbacks.
+ private ServerManagedObject<? extends S> cachedManagedObject;
- // The instantiable relation.
- private final InstantiableRelationDefinition<?, S> instantiableRelation;
+ // The instantiable relation.
+ private final InstantiableRelationDefinition<?, S> instantiableRelation;
- // The set relation.
- private final SetRelationDefinition<?, S> setRelation;
+ // The set relation.
+ private final SetRelationDefinition<?, S> setRelation;
- // The underlying add listener.
- private final ServerManagedObjectAddListener<S> listener;
+ // The underlying add listener.
+ private final ServerManagedObjectAddListener<S> listener;
- // The optional relation.
- private final OptionalRelationDefinition<?, S> optionalRelation;
+ // The optional relation.
+ private final OptionalRelationDefinition<?, S> optionalRelation;
- // The managed object path of the parent.
- private final ManagedObjectPath<?, ?> path;
+ // The managed object path of the parent.
+ private final ManagedObjectPath<?, ?> path;
+ private final ServerManagementContext serverContext;
-
- /**
- * Create a new configuration add listener adaptor for an
- * instantiable relation.
- *
- * @param path
- * The managed object path of the parent.
- * @param relation
- * The instantiable relation.
- * @param listener
- * The underlying add listener.
- */
- public ConfigAddListenerAdaptor(ManagedObjectPath<?, ?> path,
- InstantiableRelationDefinition<?, S> relation,
- ServerManagedObjectAddListener<S> listener) {
- this.path = path;
- this.instantiableRelation = relation;
- this.optionalRelation = null;
- this.setRelation = null;
- this.listener = listener;
- this.cachedManagedObject = null;
- }
-
-
-
- /**
- * Create a new configuration add listener adaptor for an optional
- * relation.
- *
- * @param path
- * The managed object path of the parent.
- * @param relation
- * The optional relation.
- * @param listener
- * The underlying add listener.
- */
- public ConfigAddListenerAdaptor(ManagedObjectPath<?, ?> path,
- OptionalRelationDefinition<?, S> relation,
- ServerManagedObjectAddListener<S> listener) {
- this.path = path;
- this.optionalRelation = relation;
- this.instantiableRelation = null;
- this.setRelation = null;
- this.listener = listener;
- this.cachedManagedObject = null;
- }
-
-
-
- /**
- * Create a new configuration add listener adaptor for a
- * set relation.
- *
- * @param path
- * The managed object path of the parent.
- * @param relation
- * The set relation.
- * @param listener
- * The underlying add listener.
- */
- public ConfigAddListenerAdaptor(ManagedObjectPath<?, ?> path,
- SetRelationDefinition<?, S> relation,
- ServerManagedObjectAddListener<S> listener) {
- this.path = path;
- this.instantiableRelation = null;
- this.optionalRelation = null;
- this.setRelation = relation;
- this.listener = listener;
- this.cachedManagedObject = null;
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- public ConfigChangeResult applyConfigurationAdd(ConfigEntry configEntry) {
- if (optionalRelation != null) {
- // Optional managed objects are located directly beneath the
- // parent and have a well-defined name. We need to make sure
- // that we are handling the correct entry.
- ManagedObjectPath<?, ?> childPath = path.child(optionalRelation);
- DN expectedDN = DNBuilder.create(childPath);
- if (!configEntry.getDN().equals(expectedDN)) {
- // Doesn't apply to us.
- return new ConfigChangeResult(ResultCode.SUCCESS, false);
- }
+ /**
+ * Create a new configuration add listener adaptor for an instantiable
+ * relation.
+ *
+ * @param context
+ * The server context.
+ * @param path
+ * The managed object path of the parent.
+ * @param relation
+ * The instantiable relation.
+ * @param listener
+ * The underlying add listener.
+ */
+ public ConfigAddListenerAdaptor(ServerManagementContext context, ManagedObjectPath<?, ?> path,
+ InstantiableRelationDefinition<?, S> relation, ServerManagedObjectAddListener<S> listener) {
+ this.serverContext = context;
+ this.path = path;
+ this.instantiableRelation = relation;
+ this.optionalRelation = null;
+ this.setRelation = null;
+ this.listener = listener;
+ this.cachedManagedObject = null;
}
- // Cached objects are guaranteed to be from previous acceptable
- // callback.
- ConfigChangeResult result = listener
- .applyConfigurationAdd(cachedManagedObject);
+ /**
+ * Create a new configuration add listener adaptor for an optional relation.
+ *
+ * @param context
+ * The server context.
+ * @param path
+ * The managed object path of the parent.
+ * @param relation
+ * The optional relation.
+ * @param listener
+ * The underlying add listener.
+ */
+ public ConfigAddListenerAdaptor(ServerManagementContext context, ManagedObjectPath<?, ?> path,
+ OptionalRelationDefinition<?, S> relation, ServerManagedObjectAddListener<S> listener) {
+ this.serverContext = context;
+ this.path = path;
+ this.optionalRelation = relation;
+ this.instantiableRelation = null;
+ this.setRelation = null;
+ this.listener = listener;
+ this.cachedManagedObject = null;
+ }
- // Now apply post constraint call-backs.
- if (result.getResultCode() == ResultCode.SUCCESS) {
- ManagedObjectDefinition<?, ?> d = cachedManagedObject
- .getManagedObjectDefinition();
- for (Constraint constraint : d.getAllConstraints()) {
- for (ServerConstraintHandler handler : constraint
- .getServerConstraintHandlers()) {
- try {
- handler.performPostAdd(cachedManagedObject);
- } catch (ConfigException e) {
- debugLogger.trace("Unable to perform post add", e);
- }
+ /**
+ * Create a new configuration add listener adaptor for a set relation.
+ *
+ * @param context
+ * The server context.
+ * @param path
+ * The managed object path of the parent.
+ * @param relation
+ * The set relation.
+ * @param listener
+ * The underlying add listener.
+ */
+ public ConfigAddListenerAdaptor(ServerManagementContext context, ManagedObjectPath<?, ?> path,
+ SetRelationDefinition<?, S> relation, ServerManagedObjectAddListener<S> listener) {
+ this.serverContext = context;
+ this.path = path;
+ this.instantiableRelation = null;
+ this.optionalRelation = null;
+ this.setRelation = relation;
+ this.listener = listener;
+ this.cachedManagedObject = null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ConfigChangeResult applyConfigurationAdd(Entry configEntry) {
+ if (optionalRelation != null) {
+ // Optional managed objects are located directly beneath the
+ // parent and have a well-defined name. We need to make sure
+ // that we are handling the correct entry.
+ ManagedObjectPath<?, ?> childPath = path.child(optionalRelation);
+ DN expectedDN = DNBuilder.create(childPath);
+ if (!configEntry.getName().equals(expectedDN)) {
+ // Doesn't apply to us.
+ return new ConfigChangeResult(ResultCode.SUCCESS, false);
+ }
}
- }
+
+ // Cached objects are guaranteed to be from previous acceptable
+ // callback.
+ ConfigChangeResult result = listener.applyConfigurationAdd(cachedManagedObject);
+
+ // Now apply post constraint call-backs.
+ if (result.getResultCode() == ResultCode.SUCCESS) {
+ ManagedObjectDefinition<?, ?> d = cachedManagedObject.getManagedObjectDefinition();
+ for (Constraint constraint : d.getAllConstraints()) {
+ for (ServerConstraintHandler handler : constraint.getServerConstraintHandlers()) {
+ try {
+ handler.performPostAdd(cachedManagedObject);
+ } catch (ConfigException e) {
+ debugLogger.trace("Unable to perform post add", e);
+ }
+ }
+ }
+ }
+
+ return result;
}
- return result;
- }
+ /**
+ * {@inheritDoc}
+ */
+ public boolean configAddIsAcceptable(Entry configEntry, LocalizableMessageBuilder unacceptableReason) {
+ DN dn = configEntry.getName();
+ String name = dn.rdn().getFirstAVA().getAttributeValue().toString().trim();
-
-
- /**
- * {@inheritDoc}
- */
- public boolean configAddIsAcceptable(ConfigEntry configEntry,
- LocalizableMessageBuilder unacceptableReason) {
- DN dn = configEntry.getDN();
- String name = dn.rdn().getFirstAVA().getAttributeValue().toString().trim();
-
- try {
- ManagedObjectPath<?, ? extends S> childPath;
- if (instantiableRelation != null) {
- childPath = path.child(instantiableRelation, name);
- } else if (setRelation != null) {
try {
- childPath = path.child(setRelation, name);
- } catch (IllegalArgumentException e) {
- throw new DefinitionDecodingException(setRelation
- .getChildDefinition(), Reason.WRONG_TYPE_INFORMATION);
+ ManagedObjectPath<?, ? extends S> childPath;
+ if (instantiableRelation != null) {
+ childPath = path.child(instantiableRelation, name);
+ } else if (setRelation != null) {
+ try {
+ childPath = path.child(setRelation, name);
+ } catch (IllegalArgumentException e) {
+ throw new DefinitionDecodingException(setRelation.getChildDefinition(),
+ Reason.WRONG_TYPE_INFORMATION);
+ }
+ } else {
+ // Optional managed objects are located directly beneath the
+ // parent and have a well-defined name. We need to make sure
+ // that we are handling the correct entry.
+ childPath = path.child(optionalRelation);
+ DN expectedDN = DNBuilder.create(childPath);
+ if (!dn.equals(expectedDN)) {
+ // Doesn't apply to us.
+ return true;
+ }
+ }
+
+ cachedManagedObject = serverContext.decode(childPath, configEntry, configEntry);
+ } catch (DecodingException e) {
+ unacceptableReason.append(e.getMessageObject());
+ return false;
}
- } else {
- // Optional managed objects are located directly beneath the
- // parent and have a well-defined name. We need to make sure
- // that we are handling the correct entry.
- childPath = path.child(optionalRelation);
- DN expectedDN = DNBuilder.create(childPath);
- if (!dn.equals(expectedDN)) {
- // Doesn't apply to us.
- return true;
+
+ // Give up immediately if a constraint violation occurs.
+ try {
+ cachedManagedObject.ensureIsUsable();
+ } catch (ConstraintViolationException e) {
+ generateUnacceptableReason(e.getMessages(), unacceptableReason);
+ return false;
}
- }
- ServerManagementContext context = ServerManagementContext.getInstance();
- cachedManagedObject = context.decode(childPath, configEntry, configEntry);
- } catch (DecodingException e) {
- unacceptableReason.append(e.getMessageObject());
- return false;
+ // Let the add listener decide.
+ List<LocalizableMessage> reasons = new LinkedList<LocalizableMessage>();
+ if (listener.isConfigurationAddAcceptable(cachedManagedObject, reasons)) {
+ return true;
+ } else {
+ generateUnacceptableReason(reasons, unacceptableReason);
+ return false;
+ }
}
- // Give up immediately if a constraint violation occurs.
- try {
- cachedManagedObject.ensureIsUsable();
- } catch (ConstraintViolationException e) {
- generateUnacceptableReason(e.getMessages(), unacceptableReason);
- return false;
+ /**
+ * Get the server managed object add listener associated with this adaptor.
+ *
+ * @return Returns the server managed object add listener associated with
+ * this adaptor.
+ */
+ ServerManagedObjectAddListener<S> getServerManagedObjectAddListener() {
+ return listener;
}
-
- // Let the add listener decide.
- List<LocalizableMessage> reasons = new LinkedList<LocalizableMessage>();
- if (listener.isConfigurationAddAcceptable(cachedManagedObject, reasons)) {
- return true;
- } else {
- generateUnacceptableReason(reasons, unacceptableReason);
- return false;
- }
- }
-
-
-
- /**
- * Get the server managed object add listener associated with this
- * adaptor.
- *
- * @return Returns the server managed object add listener associated
- * with this adaptor.
- */
- ServerManagedObjectAddListener<S> getServerManagedObjectAddListener() {
- return listener;
- }
}
diff --git a/opendj-sdk/opendj-admin/src/main/java/org/opends/server/admin/server/ConfigChangeListenerAdaptor.java b/opendj-sdk/opendj-admin/src/main/java/org/opends/server/admin/server/ConfigChangeListenerAdaptor.java
index ff7c543..8092a17 100644
--- a/opendj-sdk/opendj-admin/src/main/java/org/opends/server/admin/server/ConfigChangeListenerAdaptor.java
+++ b/opendj-sdk/opendj-admin/src/main/java/org/opends/server/admin/server/ConfigChangeListenerAdaptor.java
@@ -54,13 +54,13 @@
import org.opends.server.admin.UndefinedDefaultBehaviorProvider;
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.config.ConfigurationRepository;
import org.opends.server.types.ConfigChangeResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.forgerock.opendj.ldap.DN;
+import org.forgerock.opendj.ldap.Entry;
import org.forgerock.opendj.ldap.ResultCode;
/**
@@ -97,7 +97,8 @@
* @param dependencies
* Add dependencies names to this collection.
*/
- public static <T> void find(ManagedObjectPath<?, ?> path, PropertyDefinition<T> pd, Collection<DN> dependencies) {
+ 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);
@@ -167,39 +168,52 @@
}
}
- // Cached managed object between accept/apply call-backs.
+ /** Cached managed object between accept/apply call-backs. */
private ServerManagedObject<? extends S> cachedManagedObject;
- // The delete listener which is used to remove this listener and any
- // dependencies.
+ /**
+ * The delete listener which is used to remove this listener and any
+ * dependencies.
+ */
private final ConfigDeleteListener cleanerListener;
- // The names of entries that this change listener depends on.
+ /** 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.
+ /**
+ * The listener used to notify this listener when dependency entries are
+ * modified.
+ */
private final ConfigChangeListener dependencyListener;
- // The DN associated with this listener.
+ /** The DN associated with this listener. */
private final DN dn;
- // The underlying change listener.
+ /** The underlying change listener. */
private final ServerManagedObjectChangeListener<? super S> listener;
- // The managed object path.
+ /** The managed object path. */
private final ManagedObjectPath<?, S> path;
+ /** Repository of configuration entries */
+ private final ConfigurationRepository configRepository;
+
+ private final ServerManagementContext serverContext;
+
/**
* Create a new configuration change listener adaptor.
*
+ * @param serverContext
+ * The server context.
* @param path
* The managed object path.
* @param listener
* The underlying change listener.
*/
- public ConfigChangeListenerAdaptor(ManagedObjectPath<?, S> path,
- ServerManagedObjectChangeListener<? super S> listener) {
+ public ConfigChangeListenerAdaptor(final ServerManagementContext serverContext,
+ final ManagedObjectPath<?, S> path, final ServerManagedObjectChangeListener<? super S> listener) {
+ this.serverContext = serverContext;
+ configRepository = serverContext.getConfigRepository();
this.path = path;
this.dn = DNBuilder.create(path);
this.listener = listener;
@@ -211,26 +225,25 @@
this.dependencies = new HashSet<DN>();
this.dependencyListener = new ConfigChangeListener() {
- public ConfigChangeResult applyConfigurationChange(ConfigEntry configEntry) {
- ConfigEntry dependentConfigEntry = getConfigEntry(dn);
+ public ConfigChangeResult applyConfigurationChange(Entry configEntry) {
+ Entry dependentConfigEntry = getConfigEntry(dn);
if (dependentConfigEntry != null) {
return ConfigChangeListenerAdaptor.this.applyConfigurationChange(dependentConfigEntry);
} else {
// The dependent entry was not found.
- configEntry.deregisterChangeListener(this);
+ configRepository.deregisterChangeListener(configEntry.getName(), this);
return new ConfigChangeResult(ResultCode.SUCCESS, false);
}
}
- public boolean configChangeIsAcceptable(ConfigEntry configEntry,
- LocalizableMessageBuilder unacceptableReason) {
- ConfigEntry dependentConfigEntry = getConfigEntry(dn);
+ public boolean configChangeIsAcceptable(Entry configEntry, LocalizableMessageBuilder unacceptableReason) {
+ Entry dependentConfigEntry = getConfigEntry(dn);
if (dependentConfigEntry != null) {
return ConfigChangeListenerAdaptor.this.configChangeIsAcceptable(dependentConfigEntry,
unacceptableReason, configEntry);
} else {
// The dependent entry was not found.
- configEntry.deregisterChangeListener(this);
+ configRepository.deregisterChangeListener(configEntry.getName(), this);
return true;
}
}
@@ -246,9 +259,9 @@
// Be careful not to register listeners against the dependent
// entry itself.
if (!entryDN.equals(dn)) {
- ConfigEntry configEntry = getConfigEntry(entryDN);
+ Entry configEntry = getConfigEntry(entryDN);
if (configEntry != null) {
- configEntry.registerChangeListener(dependencyListener);
+ configRepository.registerChangeListener(configEntry.getName(), dependencyListener);
}
}
}
@@ -258,17 +271,16 @@
// entry is removed.
this.cleanerListener = new ConfigDeleteListener() {
- public ConfigChangeResult applyConfigurationDelete(ConfigEntry configEntry) {
+ public ConfigChangeResult applyConfigurationDelete(Entry configEntry) {
// Perform finalization if the deleted entry is the monitored
// entry.
- if (configEntry.getDN().equals(dn)) {
+ if (configEntry.getName().equals(dn)) {
finalizeChangeListener();
}
return new ConfigChangeResult(ResultCode.SUCCESS, false);
}
- public boolean configDeleteIsAcceptable(ConfigEntry configEntry,
- LocalizableMessageBuilder unacceptableReason) {
+ public boolean configDeleteIsAcceptable(Entry configEntry, LocalizableMessageBuilder unacceptableReason) {
// Always acceptable.
return true;
}
@@ -277,9 +289,9 @@
DN parent = dn.parent();
if (parent != null) {
- ConfigEntry configEntry = getConfigEntry(dn.parent());
+ Entry configEntry = getConfigEntry(dn.parent());
if (configEntry != null) {
- configEntry.registerDeleteListener(cleanerListener);
+ configRepository.registerDeleteListener(configEntry.getName(), cleanerListener);
}
}
}
@@ -287,13 +299,13 @@
/**
* {@inheritDoc}
*/
- public ConfigChangeResult applyConfigurationChange(ConfigEntry configEntry) {
+ public ConfigChangeResult applyConfigurationChange(Entry configEntry) {
// Looking at the ConfigFileHandler implementation reveals
// that this ConfigEntry will actually be a different object to
// 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);
+ cachedManagedObject.setConfigDN(configEntry.getName());
ConfigChangeResult result = listener.applyConfigurationChange(cachedManagedObject);
@@ -317,7 +329,7 @@
/**
* {@inheritDoc}
*/
- public boolean configChangeIsAcceptable(ConfigEntry configEntry, LocalizableMessageBuilder unacceptableReason) {
+ public boolean configChangeIsAcceptable(Entry configEntry, LocalizableMessageBuilder unacceptableReason) {
return configChangeIsAcceptable(configEntry, unacceptableReason, configEntry);
}
@@ -338,11 +350,10 @@
* @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, LocalizableMessageBuilder unacceptableReason,
- ConfigEntry newConfigEntry) {
+ public boolean configChangeIsAcceptable(Entry configEntry, LocalizableMessageBuilder unacceptableReason,
+ Entry newConfigEntry) {
try {
- ServerManagementContext context = ServerManagementContext.getInstance();
- cachedManagedObject = context.decode(path, configEntry, newConfigEntry);
+ cachedManagedObject = serverContext.decode(path, configEntry, newConfigEntry);
} catch (DecodingException e) {
unacceptableReason.append(e.getMessageObject());
return false;
@@ -373,17 +384,17 @@
public void finalizeChangeListener() {
// Remove the dependency listeners.
for (DN dependency : dependencies) {
- ConfigEntry listenerConfigEntry = getConfigEntry(dependency);
+ Entry listenerConfigEntry = getConfigEntry(dependency);
if (listenerConfigEntry != null) {
- listenerConfigEntry.deregisterChangeListener(dependencyListener);
+ configRepository.deregisterChangeListener(listenerConfigEntry.getName(), dependencyListener);
}
}
// Now remove the cleaner listener as it will no longer be
// needed.
- ConfigEntry parentConfigEntry = getConfigEntry(dn.parent());
+ Entry parentConfigEntry = getConfigEntry(dn.parent());
if (parentConfigEntry != null) {
- parentConfigEntry.deregisterDeleteListener(cleanerListener);
+ configRepository.deregisterDeleteListener(parentConfigEntry.getName(), cleanerListener);
}
}
@@ -401,11 +412,10 @@
// Returns the named configuration entry or null if it could not be
// retrieved.
- private ConfigEntry getConfigEntry(DN dn) {
+ private Entry getConfigEntry(DN dn) {
try {
- ConfigEntry configEntry = DirectoryServer.getConfigEntry(dn);
- if (configEntry != null) {
- return configEntry;
+ if (configRepository.hasEntry(dn)) {
+ return configRepository.getEntry(dn);
} else {
adminLogger.error(ERR_ADMIN_MANAGED_OBJECT_DOES_NOT_EXIST, String.valueOf(dn));
}
@@ -414,7 +424,6 @@
adminLogger.error(ERR_ADMIN_CANNOT_GET_MANAGED_OBJECT, String.valueOf(dn),
StaticUtils.getExceptionMessage(e));
}
-
return null;
}
diff --git a/opendj-sdk/opendj-admin/src/main/java/org/opends/server/admin/server/ConfigDeleteListenerAdaptor.java b/opendj-sdk/opendj-admin/src/main/java/org/opends/server/admin/server/ConfigDeleteListenerAdaptor.java
index 81a8c02..6edff02 100644
--- a/opendj-sdk/opendj-admin/src/main/java/org/opends/server/admin/server/ConfigDeleteListenerAdaptor.java
+++ b/opendj-sdk/opendj-admin/src/main/java/org/opends/server/admin/server/ConfigDeleteListenerAdaptor.java
@@ -43,10 +43,10 @@
import org.opends.server.admin.SetRelationDefinition;
import org.opends.server.admin.DefinitionDecodingException.Reason;
import org.opends.server.api.ConfigDeleteListener;
-import org.opends.server.config.ConfigEntry;
import org.opends.server.config.ConfigException;
import org.opends.server.types.ConfigChangeResult;
import org.forgerock.opendj.ldap.DN;
+import org.forgerock.opendj.ldap.Entry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.forgerock.opendj.ldap.ResultCode;
@@ -81,10 +81,14 @@
// The managed object path of the parent.
private final ManagedObjectPath<?, ?> path;
+ private final ServerManagementContext serverContext;
+
/**
* Create a new configuration delete listener adaptor for an instantiable
* relation.
*
+ * @param serverContext
+ * The server context.
* @param path
* The managed object path of the parent.
* @param relation
@@ -92,8 +96,9 @@
* @param listener
* The underlying delete listener.
*/
- public ConfigDeleteListenerAdaptor(ManagedObjectPath<?, ?> path, InstantiableRelationDefinition<?, S> relation,
- ServerManagedObjectDeleteListener<S> listener) {
+ public ConfigDeleteListenerAdaptor(ServerManagementContext serverContext, ManagedObjectPath<?, ?> path,
+ InstantiableRelationDefinition<?, S> relation, ServerManagedObjectDeleteListener<S> listener) {
+ this.serverContext = serverContext;
this.path = path;
this.optionalRelation = null;
this.instantiableRelation = relation;
@@ -105,7 +110,7 @@
/**
* Create a new configuration delete listener adaptor for an optional
* relation.
- *
+ * @param serverContext TODO
* @param path
* The managed object path of the parent.
* @param relation
@@ -113,8 +118,9 @@
* @param listener
* The underlying delete listener.
*/
- public ConfigDeleteListenerAdaptor(ManagedObjectPath<?, ?> path, OptionalRelationDefinition<?, S> relation,
- ServerManagedObjectDeleteListener<S> listener) {
+ public ConfigDeleteListenerAdaptor(ServerManagementContext serverContext, ManagedObjectPath<?, ?> path,
+ OptionalRelationDefinition<?, S> relation, ServerManagedObjectDeleteListener<S> listener) {
+ this.serverContext = serverContext;
this.path = path;
this.optionalRelation = relation;
this.instantiableRelation = null;
@@ -125,7 +131,7 @@
/**
* Create a new configuration delete listener adaptor for an set relation.
- *
+ * @param serverContext TODO
* @param path
* The managed object path of the parent.
* @param relation
@@ -133,8 +139,9 @@
* @param listener
* The underlying delete listener.
*/
- public ConfigDeleteListenerAdaptor(ManagedObjectPath<?, ?> path, SetRelationDefinition<?, S> relation,
- ServerManagedObjectDeleteListener<S> listener) {
+ public ConfigDeleteListenerAdaptor(ServerManagementContext serverContext, ManagedObjectPath<?, ?> path,
+ SetRelationDefinition<?, S> relation, ServerManagedObjectDeleteListener<S> listener) {
+ this.serverContext = serverContext;
this.path = path;
this.optionalRelation = null;
this.instantiableRelation = null;
@@ -146,14 +153,15 @@
/**
* {@inheritDoc}
*/
- public ConfigChangeResult applyConfigurationDelete(ConfigEntry configEntry) {
+ @Override
+ public ConfigChangeResult applyConfigurationDelete(Entry configEntry) {
if (optionalRelation != null) {
// Optional managed objects are located directly beneath the
// parent and have a well-defined name. We need to make sure
// that we are handling the correct entry.
ManagedObjectPath<?, ?> childPath = path.child(optionalRelation);
DN expectedDN = DNBuilder.create(childPath);
- if (!configEntry.getDN().equals(expectedDN)) {
+ if (!configEntry.getName().equals(expectedDN)) {
// Doesn't apply to us.
return new ConfigChangeResult(ResultCode.SUCCESS, false);
}
@@ -183,8 +191,8 @@
/**
* {@inheritDoc}
*/
- public boolean configDeleteIsAcceptable(ConfigEntry configEntry, LocalizableMessageBuilder unacceptableReason) {
- DN dn = configEntry.getDN();
+ public boolean configDeleteIsAcceptable(Entry configEntry, LocalizableMessageBuilder unacceptableReason) {
+ DN dn = configEntry.getName();
String name = dn.rdn().getFirstAVA().getAttributeValue().toString().trim();
try {
@@ -210,8 +218,7 @@
}
}
- ServerManagementContext context = ServerManagementContext.getInstance();
- cachedManagedObject = context.decode(childPath, configEntry);
+ cachedManagedObject = serverContext.decode(childPath, configEntry);
} catch (DecodingException e) {
unacceptableReason.append(e.getMessageObject());
return false;
diff --git a/opendj-sdk/opendj-admin/src/main/java/org/opends/server/admin/server/DelayedConfigAddListener.java b/opendj-sdk/opendj-admin/src/main/java/org/opends/server/admin/server/DelayedConfigAddListener.java
index eb17266..6188729 100644
--- a/opendj-sdk/opendj-admin/src/main/java/org/opends/server/admin/server/DelayedConfigAddListener.java
+++ b/opendj-sdk/opendj-admin/src/main/java/org/opends/server/admin/server/DelayedConfigAddListener.java
@@ -27,13 +27,13 @@
import org.opends.server.api.ConfigAddListener;
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.config.ConfigurationRepository;
import org.opends.server.types.ConfigChangeResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.forgerock.opendj.ldap.DN;
+import org.forgerock.opendj.ldap.Entry;
import org.forgerock.opendj.ldap.ResultCode;
import org.forgerock.i18n.LocalizableMessageBuilder;
@@ -62,6 +62,8 @@
// registered).
private final ConfigDeleteListener delayedDeleteListener;
+ private final ConfigurationRepository configRepository;
+
/**
* Create a new delayed add listener which will register an add listener
* with the specified entry when it is added.
@@ -72,12 +74,14 @@
* @param addListener
* The add listener to be added to the subordinate entry when it
* is added.
+ * @param configRepository TODO
*/
- public DelayedConfigAddListener(DN child, ConfigAddListener addListener) {
+ public DelayedConfigAddListener(DN child, ConfigAddListener addListener, ConfigurationRepository configRepository) {
this.parent = child.parent();
this.child = child;
this.delayedAddListener = addListener;
this.delayedDeleteListener = null;
+ this.configRepository = configRepository;
}
/**
@@ -90,34 +94,35 @@
* @param deleteListener
* The delete listener to be added to the subordinate entry when
* it is added.
+ * @param configRepository TODO
*/
- public DelayedConfigAddListener(DN child, ConfigDeleteListener deleteListener) {
+ public DelayedConfigAddListener(DN child, ConfigDeleteListener deleteListener, ConfigurationRepository configRepository) {
this.parent = child.parent();
this.child = child;
this.delayedAddListener = null;
+ this.configRepository = configRepository;
this.delayedDeleteListener = deleteListener;
}
/**
* {@inheritDoc}
*/
- public ConfigChangeResult applyConfigurationAdd(ConfigEntry configEntry) {
- if (configEntry.getDN().equals(child)) {
+ public ConfigChangeResult applyConfigurationAdd(Entry configEntry) {
+ if (configEntry.getName().equals(child)) {
// The subordinate entry matched our criteria so register the
// listener(s).
if (delayedAddListener != null) {
- configEntry.registerAddListener(delayedAddListener);
+ configRepository.registerAddListener(configEntry.getName(), delayedAddListener);
}
if (delayedDeleteListener != null) {
- configEntry.registerDeleteListener(delayedDeleteListener);
+ configRepository.registerDeleteListener(configEntry.getName(), delayedDeleteListener);
}
- // We are no longer needed.
try {
- ConfigEntry myEntry = DirectoryServer.getConfigEntry(parent);
- if (myEntry != null) {
- myEntry.deregisterAddListener(this);
+ // We are no longer needed.
+ if (configRepository.hasEntry(parent)) {
+ configRepository.deregisterAddListener(parent, this);
}
} catch (ConfigException e) {
debugLogger.trace("Unable to deregister add listener", e);
@@ -132,7 +137,7 @@
/**
* {@inheritDoc}
*/
- public boolean configAddIsAcceptable(ConfigEntry configEntry, LocalizableMessageBuilder unacceptableReason) {
+ public boolean configAddIsAcceptable(Entry configEntry, LocalizableMessageBuilder unacceptableReason) {
// Always acceptable.
return true;
}
diff --git a/opendj-sdk/opendj-admin/src/main/java/org/opends/server/admin/server/ServerManagedObject.java b/opendj-sdk/opendj-admin/src/main/java/org/opends/server/admin/server/ServerManagedObject.java
index 1ea7c61..5d82dee 100644
--- a/opendj-sdk/opendj-admin/src/main/java/org/opends/server/admin/server/ServerManagedObject.java
+++ b/opendj-sdk/opendj-admin/src/main/java/org/opends/server/admin/server/ServerManagedObject.java
@@ -27,7 +27,6 @@
package org.opends.server.admin.server;
import static com.forgerock.opendj.ldap.AdminMessages.*;
-import static com.forgerock.opendj.util.StaticUtils.*;
import java.util.Collections;
import java.util.LinkedList;
@@ -52,13 +51,13 @@
import org.opends.server.api.ConfigAddListener;
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.util.DynamicConstants;
+import org.opends.server.config.ConfigurationRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.forgerock.opendj.util.Pair;
+
/**
* A server-side managed object.
@@ -71,21 +70,21 @@
private static final Logger logger = LoggerFactory.getLogger(ServerManagedObject.class);
- // The configuration entry associated with this server managed
- // object (null if root).
- private ConfigEntry configEntry;
+ /**
+ * The DN of configuration entry associated with this server managed object,
+ * which is {@code null} for root.
+ */
+ private DN configDN;
- // The management context.
- private final ServerManagementContext context = ServerManagementContext.getInstance();
+ private final ServerManagementContext serverContext;
- // The managed object's definition.
+ private final ConfigurationRepository configRepository;
+
private final ManagedObjectDefinition<?, S> definition;
- // The managed object path identifying this managed object's
- // location.
+ /** The managed object path identifying this managed object's location */
private final ManagedObjectPath<?, S> path;
- // The managed object's properties.
private final Map<PropertyDefinition<?>, SortedSet<?>> properties;
/**
@@ -97,15 +96,20 @@
* The managed object definition.
* @param properties
* The managed object's properties.
- * @param configEntry
+ * @param configDN
* The configuration entry associated with the managed object.
+ * @param context
+ * The server management context.
*/
- ServerManagedObject(ManagedObjectPath<?, S> path, ManagedObjectDefinition<?, S> d,
- Map<PropertyDefinition<?>, SortedSet<?>> properties, ConfigEntry configEntry) {
+ ServerManagedObject(final ManagedObjectPath<?, S> path, final ManagedObjectDefinition<?, S> d,
+ final Map<PropertyDefinition<?>, SortedSet<?>> properties, final DN configDN,
+ final ServerManagementContext context) {
this.definition = d;
this.path = path;
this.properties = properties;
- this.configEntry = configEntry;
+ this.configDN = configDN;
+ this.serverContext = context;
+ this.configRepository = context.getConfigRepository();
}
/**
@@ -124,7 +128,6 @@
public <M extends Configuration> void deregisterAddListener(InstantiableRelationDefinition<?, M> d,
ConfigurationAddListener<M> listener) throws IllegalArgumentException {
validateRelationDefinition(d);
-
DN baseDN = DNBuilder.create(path, d);
deregisterAddListener(baseDN, listener);
}
@@ -145,7 +148,6 @@
public <M extends Configuration> void deregisterAddListener(InstantiableRelationDefinition<?, M> d,
ServerManagedObjectAddListener<M> listener) throws IllegalArgumentException {
validateRelationDefinition(d);
-
DN baseDN = DNBuilder.create(path, d);
deregisterAddListener(baseDN, listener);
}
@@ -166,7 +168,6 @@
public <M extends Configuration> void deregisterAddListener(OptionalRelationDefinition<?, M> d,
ConfigurationAddListener<M> listener) throws IllegalArgumentException {
validateRelationDefinition(d);
-
DN baseDN = DNBuilder.create(path, d).parent();
deregisterAddListener(baseDN, listener);
}
@@ -187,7 +188,6 @@
public <M extends Configuration> void deregisterAddListener(OptionalRelationDefinition<?, M> d,
ServerManagedObjectAddListener<M> listener) throws IllegalArgumentException {
validateRelationDefinition(d);
-
DN baseDN = DNBuilder.create(path, d).parent();
deregisterAddListener(baseDN, listener);
}
@@ -208,7 +208,6 @@
public <M extends Configuration> void deregisterAddListener(SetRelationDefinition<?, M> d,
ConfigurationAddListener<M> listener) throws IllegalArgumentException {
validateRelationDefinition(d);
-
DN baseDN = DNBuilder.create(path, d);
deregisterAddListener(baseDN, listener);
}
@@ -229,7 +228,6 @@
public <M extends Configuration> void deregisterAddListener(SetRelationDefinition<?, M> d,
ServerManagedObjectAddListener<M> listener) throws IllegalArgumentException {
validateRelationDefinition(d);
-
DN baseDN = DNBuilder.create(path, d);
deregisterAddListener(baseDN, listener);
}
@@ -241,7 +239,7 @@
* The configuration change listener.
*/
public void deregisterChangeListener(ConfigurationChangeListener<? super S> listener) {
- for (ConfigChangeListener l : configEntry.getChangeListeners()) {
+ for (ConfigChangeListener l : configRepository.getChangeListeners(configDN)) {
if (l instanceof ConfigChangeListenerAdaptor) {
ConfigChangeListenerAdaptor<?> adaptor = (ConfigChangeListenerAdaptor<?>) l;
ServerManagedObjectChangeListener<?> l2 = adaptor.getServerManagedObjectChangeListener();
@@ -249,7 +247,7 @@
ServerManagedObjectChangeListenerAdaptor<?> adaptor2 = (ServerManagedObjectChangeListenerAdaptor<?>) l2;
if (adaptor2.getConfigurationChangeListener() == listener) {
adaptor.finalizeChangeListener();
- configEntry.deregisterChangeListener(adaptor);
+ configRepository.deregisterChangeListener(configDN, adaptor);
}
}
}
@@ -263,12 +261,12 @@
* The server managed object change listener.
*/
public void deregisterChangeListener(ServerManagedObjectChangeListener<? super S> listener) {
- for (ConfigChangeListener l : configEntry.getChangeListeners()) {
+ for (ConfigChangeListener l : configRepository.getChangeListeners(configDN)) {
if (l instanceof ConfigChangeListenerAdaptor) {
ConfigChangeListenerAdaptor<?> adaptor = (ConfigChangeListenerAdaptor<?>) l;
if (adaptor.getServerManagedObjectChangeListener() == listener) {
adaptor.finalizeChangeListener();
- configEntry.deregisterChangeListener(adaptor);
+ configRepository.deregisterChangeListener(configDN, adaptor);
}
}
}
@@ -421,7 +419,7 @@
public <M extends Configuration> ServerManagedObject<? extends M> getChild(InstantiableRelationDefinition<?, M> d,
String name) throws IllegalArgumentException, ConfigException {
validateRelationDefinition(d);
- return context.getManagedObject(path.child(d, name));
+ return serverContext.getManagedObject(path.child(d, name));
}
/**
@@ -443,7 +441,7 @@
public <M extends Configuration> ServerManagedObject<? extends M> getChild(OptionalRelationDefinition<?, M> d)
throws IllegalArgumentException, ConfigException {
validateRelationDefinition(d);
- return context.getManagedObject(path.child(d));
+ return serverContext.getManagedObject(path.child(d));
}
/**
@@ -470,7 +468,7 @@
String name) throws IllegalArgumentException, ConfigException {
validateRelationDefinition(d);
- return context.getManagedObject(path.child(d, name));
+ return serverContext.getManagedObject(path.child(d, name));
}
/**
@@ -492,7 +490,16 @@
public <M extends Configuration> ServerManagedObject<? extends M> getChild(SingletonRelationDefinition<?, M> d)
throws IllegalArgumentException, ConfigException {
validateRelationDefinition(d);
- return context.getManagedObject(path.child(d));
+ return serverContext.getManagedObject(path.child(d));
+ }
+
+ /**
+ * Returns the server management context used by this object.
+ *
+ * @return the context
+ */
+ public ServerManagementContext getServerContext() {
+ return serverContext;
}
/**
@@ -511,8 +518,8 @@
* managed object, or an null DN if this is the root managed object.
*/
public DN getDN() {
- if (configEntry != null) {
- return configEntry.getDN();
+ if (configDN != null) {
+ return configDN;
} else {
return DN.rootDN();
}
@@ -600,7 +607,7 @@
*/
public boolean hasChild(OptionalRelationDefinition<?, ?> d) throws IllegalArgumentException {
validateRelationDefinition(d);
- return context.managedObjectExists(path.child(d));
+ return serverContext.managedObjectExists(path.child(d));
}
/**
@@ -616,7 +623,7 @@
*/
public String[] listChildren(InstantiableRelationDefinition<?, ?> d) throws IllegalArgumentException {
validateRelationDefinition(d);
- return context.listManagedObjects(path, d);
+ return serverContext.listManagedObjects(path, d);
}
/**
@@ -632,7 +639,7 @@
*/
public String[] listChildren(SetRelationDefinition<?, ?> d) throws IllegalArgumentException {
validateRelationDefinition(d);
- return context.listManagedObjects(path, d);
+ return serverContext.listManagedObjects(path, d);
}
/**
@@ -678,7 +685,7 @@
ServerManagedObjectAddListener<M> listener) throws IllegalArgumentException, ConfigException {
validateRelationDefinition(d);
DN baseDN = DNBuilder.create(path, d);
- ConfigAddListener adaptor = new ConfigAddListenerAdaptor<M>(path, d, listener);
+ ConfigAddListener adaptor = new ConfigAddListenerAdaptor<M>(serverContext, path, d, listener);
registerAddListener(baseDN, adaptor);
}
@@ -725,7 +732,7 @@
ServerManagedObjectAddListener<M> listener) throws IllegalArgumentException, ConfigException {
validateRelationDefinition(d);
DN baseDN = DNBuilder.create(path, d).parent();
- ConfigAddListener adaptor = new ConfigAddListenerAdaptor<M>(path, d, listener);
+ ConfigAddListener adaptor = new ConfigAddListenerAdaptor<M>(serverContext, path, d, listener);
registerAddListener(baseDN, adaptor);
}
@@ -772,7 +779,7 @@
ServerManagedObjectAddListener<M> listener) throws IllegalArgumentException, ConfigException {
validateRelationDefinition(d);
DN baseDN = DNBuilder.create(path, d);
- ConfigAddListener adaptor = new ConfigAddListenerAdaptor<M>(path, d, listener);
+ ConfigAddListener adaptor = new ConfigAddListenerAdaptor<M>(serverContext, path, d, listener);
registerAddListener(baseDN, adaptor);
}
@@ -793,8 +800,9 @@
* The server managed object change listener.
*/
public void registerChangeListener(ServerManagedObjectChangeListener<? super S> listener) {
- ConfigChangeListener adaptor = new ConfigChangeListenerAdaptor<S>(path, listener);
- configEntry.registerChangeListener(adaptor);
+
+ ConfigChangeListener adaptor = new ConfigChangeListenerAdaptor<S>(serverContext, path, listener);
+ configRepository.registerChangeListener(configDN, adaptor);
// TODO : go toward this
// Entry entry;
@@ -860,7 +868,7 @@
ServerManagedObjectDeleteListener<M> listener) throws IllegalArgumentException, ConfigException {
validateRelationDefinition(d);
DN baseDN = DNBuilder.create(path, d);
- ConfigDeleteListener adaptor = new ConfigDeleteListenerAdaptor<M>(path, d, listener);
+ ConfigDeleteListener adaptor = new ConfigDeleteListenerAdaptor<M>(serverContext, path, d, listener);
registerDeleteListener(baseDN, adaptor);
}
@@ -907,7 +915,7 @@
ServerManagedObjectDeleteListener<M> listener) throws IllegalArgumentException, ConfigException {
validateRelationDefinition(d);
DN baseDN = DNBuilder.create(path, d).parent();
- ConfigDeleteListener adaptor = new ConfigDeleteListenerAdaptor<M>(path, d, listener);
+ ConfigDeleteListener adaptor = new ConfigDeleteListenerAdaptor<M>(serverContext, path, d, listener);
registerDeleteListener(baseDN, adaptor);
}
@@ -954,7 +962,7 @@
ServerManagedObjectDeleteListener<M> listener) throws IllegalArgumentException, ConfigException {
validateRelationDefinition(d);
DN baseDN = DNBuilder.create(path, d);
- ConfigDeleteListener adaptor = new ConfigDeleteListenerAdaptor<M>(path, d, listener);
+ ConfigDeleteListener adaptor = new ConfigDeleteListenerAdaptor<M>(serverContext, path, d, listener);
registerDeleteListener(baseDN, adaptor);
}
@@ -1012,30 +1020,29 @@
}
/**
- * Update the config entry associated with this server managed object. This
+ * Update the config DN associated with this server managed object. This
* is only intended to be used by change listener call backs in order to
- * update the managed object with the correct config entry.
+ * update the managed object with the correct config DN.
*
- * @param configEntry
- * The configuration entry.
+ * @param configDN
+ * The DN of the underlying configuration entry.
*/
- void setConfigEntry(ConfigEntry configEntry) {
- this.configEntry = configEntry;
+ void setConfigDN(DN configDN) {
+ this.configDN = configDN;
}
// Deregister an add listener.
private <M extends Configuration> void deregisterAddListener(DN baseDN, ConfigurationAddListener<M> listener) {
try {
- ConfigEntry configEntry = getListenerConfigEntry(baseDN);
- if (configEntry != null) {
- for (ConfigAddListener l : configEntry.getAddListeners()) {
- if (l instanceof ConfigAddListenerAdaptor) {
- ConfigAddListenerAdaptor<?> adaptor = (ConfigAddListenerAdaptor<?>) l;
- ServerManagedObjectAddListener<?> l2 = adaptor.getServerManagedObjectAddListener();
- if (l2 instanceof ServerManagedObjectAddListenerAdaptor<?>) {
- ServerManagedObjectAddListenerAdaptor<?> adaptor2 = (ServerManagedObjectAddListenerAdaptor<?>) l2;
+ if (configRepository.hasEntry(baseDN)) {
+ for (ConfigAddListener configListener : configRepository.getAddListeners(baseDN)) {
+ if (configListener instanceof ConfigAddListenerAdaptor) {
+ ConfigAddListenerAdaptor<?> adaptor = (ConfigAddListenerAdaptor<?>) configListener;
+ ServerManagedObjectAddListener<?> smoListener = adaptor.getServerManagedObjectAddListener();
+ if (smoListener instanceof ServerManagedObjectAddListenerAdaptor<?>) {
+ ServerManagedObjectAddListenerAdaptor<?> adaptor2 = (ServerManagedObjectAddListenerAdaptor<?>) smoListener;
if (adaptor2.getConfigurationAddListener() == listener) {
- configEntry.deregisterAddListener(adaptor);
+ configRepository.deregisterAddListener(baseDN, adaptor);
}
}
}
@@ -1054,13 +1061,12 @@
// Deregister an add listener.
private <M extends Configuration> void deregisterAddListener(DN baseDN, ServerManagedObjectAddListener<M> listener) {
try {
- ConfigEntry configEntry = getListenerConfigEntry(baseDN);
- if (configEntry != null) {
- for (ConfigAddListener l : configEntry.getAddListeners()) {
- if (l instanceof ConfigAddListenerAdaptor) {
- ConfigAddListenerAdaptor<?> adaptor = (ConfigAddListenerAdaptor<?>) l;
+ if (configRepository.hasEntry(baseDN)) {
+ for (ConfigAddListener configListener : configRepository.getAddListeners(baseDN)) {
+ if (configListener instanceof ConfigAddListenerAdaptor) {
+ ConfigAddListenerAdaptor<?> adaptor = (ConfigAddListenerAdaptor<?>) configListener;
if (adaptor.getServerManagedObjectAddListener() == listener) {
- configEntry.deregisterAddListener(adaptor);
+ configRepository.deregisterAddListener(baseDN, adaptor);
}
}
}
@@ -1075,19 +1081,62 @@
}
}
+ /**
+ * Convenience method to retrieve the initial listener and its intermediate
+ * adaptor from the provided configListener.
+ *
+ * @param <T>
+ * Type of the configuration.
+ * @param configListener
+ * Listener from wich to extract the initial listener.
+ * @return a pair of (intermediate adaptor, intermediate listener) or
+ * {@code Pair.EMPTY} if listener can't be extracted
+ */
+ static <T extends Configuration> Pair<ConfigAddListenerAdaptor<T>, ConfigurationAddListener<T>>
+ extractInitialListener(ConfigAddListener configListener) {
+ Pair<ConfigAddListenerAdaptor<T>, ServerManagedObjectAddListener<T>> pair =
+ extractIntermediateListener(configListener);
+ if (!pair.equals(Pair.EMPTY) && pair.getSecond() instanceof ServerManagedObjectAddListenerAdaptor) {
+ ServerManagedObjectAddListenerAdaptor<T> adaptor2 = (ServerManagedObjectAddListenerAdaptor<T>)
+ pair.getSecond();
+ return Pair.of(pair.getFirst(), adaptor2.getConfigurationAddListener());
+ }
+ return Pair.empty();
+ }
+
+ /**
+ * Convenience method to retrieve the intermediate listener and its
+ * intermediate adaptor from the provided configListener.
+ *
+ * @param <T>
+ * Type of the configuration.
+ * @param configListener
+ * Listener from wich to extract the initial listener.
+ * @return a pair of (intermediate adaptor, initial listener) or
+ * {@code Pair.EMPTY} if listener can't be extracted
+ */
+ @SuppressWarnings("unchecked")
+ static <T extends Configuration> Pair<ConfigAddListenerAdaptor<T>, ServerManagedObjectAddListener<T>>
+ extractIntermediateListener(ConfigAddListener configListener) {
+ if (configListener instanceof ConfigAddListenerAdaptor) {
+ ConfigAddListenerAdaptor<T> adaptor = ((ConfigAddListenerAdaptor<T>) configListener);
+ return Pair.of(adaptor, adaptor.getServerManagedObjectAddListener());
+ }
+ return Pair.empty();
+ }
+
// Deregister a delete listener.
private <M extends Configuration> void deregisterDeleteListener(DN baseDN, ConfigurationDeleteListener<M> listener) {
try {
- ConfigEntry configEntry = getListenerConfigEntry(baseDN);
- if (configEntry != null) {
- for (ConfigDeleteListener l : configEntry.getDeleteListeners()) {
+ if (configRepository.hasEntry(baseDN)) {
+ for (ConfigDeleteListener l : configRepository.getDeleteListeners(baseDN)) {
if (l instanceof ConfigDeleteListenerAdaptor) {
ConfigDeleteListenerAdaptor<?> adaptor = (ConfigDeleteListenerAdaptor<?>) l;
ServerManagedObjectDeleteListener<?> l2 = adaptor.getServerManagedObjectDeleteListener();
if (l2 instanceof ServerManagedObjectDeleteListenerAdaptor<?>) {
ServerManagedObjectDeleteListenerAdaptor<?> adaptor2 = (ServerManagedObjectDeleteListenerAdaptor<?>) l2;
if (adaptor2.getConfigurationDeleteListener() == listener) {
- configEntry.deregisterDeleteListener(adaptor);
+ configRepository.deregisterDeleteListener(baseDN, adaptor);
}
}
}
@@ -1107,13 +1156,12 @@
private <M extends Configuration> void deregisterDeleteListener(DN baseDN,
ServerManagedObjectDeleteListener<M> listener) {
try {
- ConfigEntry configEntry = getListenerConfigEntry(baseDN);
- if (configEntry != null) {
- for (ConfigDeleteListener l : configEntry.getDeleteListeners()) {
+ if (configRepository.hasEntry(baseDN)) {
+ for (ConfigDeleteListener l : configRepository.getDeleteListeners(baseDN)) {
if (l instanceof ConfigDeleteListenerAdaptor) {
ConfigDeleteListenerAdaptor<?> adaptor = (ConfigDeleteListenerAdaptor<?>) l;
if (adaptor.getServerManagedObjectDeleteListener() == listener) {
- configEntry.deregisterDeleteListener(adaptor);
+ configRepository.deregisterDeleteListener(baseDN, adaptor);
}
}
}
@@ -1128,34 +1176,15 @@
}
}
- // Gets a config entry required for a listener and throws a config
- // exception on failure or returns null if the entry does not exist.
- private ConfigEntry getListenerConfigEntry(DN dn) throws ConfigException {
- // Attempt to retrieve the listener base entry.
- ConfigEntry configEntry;
- try {
- configEntry = DirectoryServer.getConfigEntry(dn);
- } catch (ConfigException e) {
- logger.trace("Unable to get listener base entry", e);
- LocalizableMessage message = ERR_ADMIN_CANNOT_GET_LISTENER_BASE.get(String.valueOf(dn),
- stackTraceToSingleLineString(e, DynamicConstants.DEBUG_BUILD));
- throw new ConfigException(message, e);
- }
-
- return configEntry;
- }
-
// Register an instantiable or optional relation add listener.
private void registerAddListener(DN baseDN, ConfigAddListener adaptor) throws IllegalArgumentException,
ConfigException {
- ConfigEntry relationEntry = getListenerConfigEntry(baseDN);
-
- if (relationEntry != null) {
- relationEntry.registerAddListener(adaptor);
+ if (configRepository.hasEntry(baseDN)) {
+ configRepository.registerAddListener(baseDN, adaptor);
} else {
- // The relation entry does not exist yet so register a delayed
- // add listener.
- ConfigAddListener delayedListener = new DelayedConfigAddListener(baseDN, adaptor);
+ // The relation entry does not exist yet
+ // so register a delayed add listener.
+ ConfigAddListener delayedListener = new DelayedConfigAddListener(baseDN, adaptor, configRepository);
registerDelayedListener(baseDN, delayedListener);
}
}
@@ -1163,14 +1192,15 @@
// Register a delayed listener with the nearest existing parent
// entry to the provided base DN.
private void registerDelayedListener(DN baseDN, ConfigAddListener delayedListener) throws ConfigException {
- DN parentDN = baseDN.parent();
- while (parentDN != null) {
- ConfigEntry relationEntry = getListenerConfigEntry(parentDN);
- if (relationEntry == null) {
- delayedListener = new DelayedConfigAddListener(parentDN, delayedListener);
- parentDN = parentDN.parent();
+ DN currentDN = baseDN.parent();
+ DN previousDN = currentDN;
+ while (currentDN != null) {
+ if (!configRepository.hasEntry(currentDN)) {
+ delayedListener = new DelayedConfigAddListener(currentDN, delayedListener, configRepository);
+ previousDN = currentDN;
+ currentDN = currentDN.parent();
} else {
- relationEntry.registerAddListener(delayedListener);
+ configRepository.registerAddListener(previousDN, delayedListener);
return;
}
}
@@ -1187,30 +1217,28 @@
DN parentDN = baseDN.parent();
int delayWrappers = 0;
while (parentDN != null) {
- ConfigEntry relationEntry = getListenerConfigEntry(parentDN);
- if (relationEntry == null) {
+ if (!configRepository.hasEntry(parentDN)) {
parentDN = parentDN.parent();
delayWrappers++;
} else {
- for (ConfigAddListener l : relationEntry.getAddListeners()) {
- if (l instanceof DelayedConfigAddListener) {
- DelayedConfigAddListener delayListener = (DelayedConfigAddListener) l;
+ for (ConfigAddListener configListener : configRepository.getAddListeners(parentDN)) {
+ if (configListener instanceof DelayedConfigAddListener) {
+ DelayedConfigAddListener delayListener = (DelayedConfigAddListener) configListener;
ConfigAddListener wrappedListener;
int i = delayWrappers;
for (; i > 0; i--) {
wrappedListener = delayListener.getDelayedAddListener();
if (wrappedListener != null && wrappedListener instanceof DelayedConfigAddListener) {
- delayListener = (DelayedConfigAddListener) l;
+ delayListener = (DelayedConfigAddListener) configListener;
} else {
break;
}
}
if (i > 0) {
- // There are not enough level of wrapping so this
- // can't be
- // the listener we are looking for.
+ // There are not enough level of wrapping
+ // so this can't be the listener we are looking for.
continue;
}
@@ -1222,7 +1250,7 @@
if (l2 instanceof ServerManagedObjectAddListenerAdaptor<?>) {
ServerManagedObjectAddListenerAdaptor<?> adaptor2 = (ServerManagedObjectAddListenerAdaptor<?>) l2;
if (adaptor2.getConfigurationAddListener() == listener) {
- relationEntry.deregisterAddListener(l);
+ configRepository.deregisterAddListener(parentDN, configListener);
}
}
}
@@ -1240,12 +1268,11 @@
DN parentDN = baseDN.parent();
int delayWrappers = 0;
while (parentDN != null) {
- ConfigEntry relationEntry = getListenerConfigEntry(parentDN);
- if (relationEntry == null) {
+ if (!configRepository.hasEntry(parentDN)) {
parentDN = parentDN.parent();
delayWrappers++;
} else {
- for (ConfigAddListener l : relationEntry.getAddListeners()) {
+ for (ConfigAddListener l : configRepository.getAddListeners(parentDN)) {
if (l instanceof DelayedConfigAddListener) {
DelayedConfigAddListener delayListener = (DelayedConfigAddListener) l;
ConfigAddListener wrappedListener;
@@ -1261,9 +1288,8 @@
}
if (i > 0) {
- // There are not enough level of wrapping so this
- // can't be
- // the listener we are looking for.
+ // There are not enough level of wrapping
+ // so this can't be the listener we are looking for.
continue;
}
@@ -1275,7 +1301,7 @@
if (l2 instanceof ServerManagedObjectDeleteListenerAdaptor<?>) {
ServerManagedObjectDeleteListenerAdaptor<?> adaptor2 = (ServerManagedObjectDeleteListenerAdaptor<?>) l2;
if (adaptor2.getConfigurationDeleteListener() == listener) {
- relationEntry.deregisterAddListener(l);
+ configRepository.deregisterAddListener(parentDN, l);
}
}
}
@@ -1293,30 +1319,28 @@
DN parentDN = baseDN.parent();
int delayWrappers = 0;
while (parentDN != null) {
- ConfigEntry relationEntry = getListenerConfigEntry(parentDN);
- if (relationEntry == null) {
+ if (!configRepository.hasEntry(parentDN)) {
parentDN = parentDN.parent();
delayWrappers++;
} else {
- for (ConfigAddListener l : relationEntry.getAddListeners()) {
- if (l instanceof DelayedConfigAddListener) {
- DelayedConfigAddListener delayListener = (DelayedConfigAddListener) l;
+ for (ConfigAddListener configListener : configRepository.getAddListeners(parentDN)) {
+ if (configListener instanceof DelayedConfigAddListener) {
+ DelayedConfigAddListener delayListener = (DelayedConfigAddListener) configListener;
ConfigAddListener wrappedListener;
int i = delayWrappers;
for (; i > 0; i--) {
wrappedListener = delayListener.getDelayedAddListener();
if (wrappedListener != null && wrappedListener instanceof DelayedConfigAddListener) {
- delayListener = (DelayedConfigAddListener) l;
+ delayListener = (DelayedConfigAddListener) configListener;
} else {
break;
}
}
if (i > 0) {
- // There are not enough level of wrapping so this
- // can't be
- // the listener we are looking for.
+ // There are not enough level of wrapping
+ // so this can't be the listener we are looking for.
continue;
}
@@ -1325,7 +1349,7 @@
if (delayedListener != null && delayedListener instanceof ConfigAddListenerAdaptor) {
ConfigAddListenerAdaptor<?> adaptor = (ConfigAddListenerAdaptor<?>) delayedListener;
if (adaptor.getServerManagedObjectAddListener() == listener) {
- relationEntry.deregisterAddListener(l);
+ configRepository.deregisterAddListener(parentDN, configListener);
}
}
}
@@ -1342,30 +1366,28 @@
DN parentDN = baseDN.parent();
int delayWrappers = 0;
while (parentDN != null) {
- ConfigEntry relationEntry = getListenerConfigEntry(parentDN);
- if (relationEntry == null) {
+ if (!configRepository.hasEntry(parentDN)) {
parentDN = parentDN.parent();
delayWrappers++;
} else {
- for (ConfigAddListener l : relationEntry.getAddListeners()) {
- if (l instanceof DelayedConfigAddListener) {
- DelayedConfigAddListener delayListener = (DelayedConfigAddListener) l;
+ for (ConfigAddListener configListener : configRepository.getAddListeners(parentDN)) {
+ if (configListener instanceof DelayedConfigAddListener) {
+ DelayedConfigAddListener delayListener = (DelayedConfigAddListener) configListener;
ConfigAddListener wrappedListener;
int i = delayWrappers;
for (; i > 0; i--) {
wrappedListener = delayListener.getDelayedAddListener();
if (wrappedListener != null && wrappedListener instanceof DelayedConfigAddListener) {
- delayListener = (DelayedConfigAddListener) l;
+ delayListener = (DelayedConfigAddListener) configListener;
} else {
break;
}
}
if (i > 0) {
- // There are not enough level of wrapping so this
- // can't be
- // the listener we are looking for.
+ // There are not enough level of wrapping
+ // so this can't be the listener we are looking for.
continue;
}
@@ -1374,7 +1396,7 @@
if (delayedListener != null && delayedListener instanceof ConfigDeleteListenerAdaptor) {
ConfigDeleteListenerAdaptor<?> adaptor = (ConfigDeleteListenerAdaptor<?>) delayedListener;
if (adaptor.getServerManagedObjectDeleteListener() == listener) {
- relationEntry.deregisterAddListener(l);
+ configRepository.deregisterAddListener(parentDN, configListener);
}
}
}
@@ -1386,14 +1408,12 @@
// Register an instantiable or optional relation delete listener.
private void registerDeleteListener(DN baseDN, ConfigDeleteListener adaptor) throws ConfigException {
- ConfigEntry relationEntry = getListenerConfigEntry(baseDN);
-
- if (relationEntry != null) {
- relationEntry.registerDeleteListener(adaptor);
+ if (configRepository.hasEntry(baseDN)) {
+ configRepository.registerDeleteListener(baseDN, adaptor);
} else {
- // The relation entry does not exist yet so register a delayed
- // add listener.
- ConfigAddListener delayedListener = new DelayedConfigAddListener(baseDN, adaptor);
+ // The relation entry does not exist yet
+ // so register a delayed add listener.
+ ConfigAddListener delayedListener = new DelayedConfigAddListener(baseDN, adaptor, configRepository);
registerDelayedListener(baseDN, delayedListener);
}
}
diff --git a/opendj-sdk/opendj-admin/src/main/java/org/opends/server/admin/server/ServerManagementContext.java b/opendj-sdk/opendj-admin/src/main/java/org/opends/server/admin/server/ServerManagementContext.java
index 0cee2a1..f96d156 100644
--- a/opendj-sdk/opendj-admin/src/main/java/org/opends/server/admin/server/ServerManagementContext.java
+++ b/opendj-sdk/opendj-admin/src/main/java/org/opends/server/admin/server/ServerManagementContext.java
@@ -71,14 +71,15 @@
import org.opends.server.admin.UndefinedDefaultBehaviorProvider;
import org.opends.server.admin.UnknownPropertyDefinitionException;
import org.opends.server.admin.DefinitionDecodingException.Reason;
-import org.opends.server.config.ConfigEntry;
import org.opends.server.config.ConfigException;
+import org.opends.server.config.ConfigurationRepository;
import org.opends.server.core.DirectoryServer;
import org.forgerock.opendj.admin.meta.RootCfgDefn;
import org.forgerock.opendj.admin.server.RootCfg;
import org.forgerock.opendj.ldap.Attribute;
import org.forgerock.opendj.ldap.AttributeDescription;
import org.forgerock.opendj.ldap.DN;
+import org.forgerock.opendj.ldap.Entry;
import org.forgerock.opendj.ldap.schema.AttributeType;
import org.opends.server.util.DynamicConstants;
import org.slf4j.Logger;
@@ -104,7 +105,7 @@
// Optional new configuration entry which does not yet exist in
// the configuration back-end.
- private final ConfigEntry newConfigEntry;
+ private final Entry newConfigEntry;
// The path of the managed object containing the next property.
private ManagedObjectPath<?, ?> nextPath = null;
@@ -113,7 +114,7 @@
private PropertyDefinition<T> nextProperty = null;
// Private constructor.
- private DefaultValueFinder(ConfigEntry newConfigEntry) {
+ private DefaultValueFinder(Entry newConfigEntry) {
this.newConfigEntry = newConfigEntry;
}
@@ -197,7 +198,7 @@
// Get an inherited property value.
@SuppressWarnings("unchecked")
- private Collection<T> getInheritedProperty(ManagedObjectPath target,
+ private Collection<T> getInheritedProperty(ManagedObjectPath<?,?> target,
AbstractManagedObjectDefinition<?, ?> definition, String propertyName)
throws DefaultBehaviorException {
// First check that the requested type of managed object
@@ -214,8 +215,8 @@
try {
// Get the actual managed object definition.
DN dn = DNBuilder.create(target);
- ConfigEntry configEntry;
- if (newConfigEntry != null && newConfigEntry.getDN().equals(dn)) {
+ Entry configEntry;
+ if (newConfigEntry != null && newConfigEntry.getName().equals(dn)) {
configEntry = newConfigEntry;
} else {
configEntry = getManagedObjectConfigEntry(dn);
@@ -273,10 +274,10 @@
private class MyDefinitionResolver implements DefinitionResolver {
// The config entry.
- private final ConfigEntry entry;
+ private final Entry entry;
// Private constructor.
- private MyDefinitionResolver(ConfigEntry entry) {
+ private MyDefinitionResolver(Entry entry) {
this.entry = entry;
}
@@ -285,7 +286,15 @@
*/
public boolean matches(AbstractManagedObjectDefinition<?, ?> d) {
String oc = LDAPProfile.getInstance().getObjectClass(d);
- return entry.hasObjectClass(oc);
+ // TODO : use the schema to get object class and check it in the entry
+ // Commented because reject any config entry without proper schema loading
+ // Previous code was
+// ObjectClass oc = DirectoryServer.getObjectClass(name.toLowerCase());
+// if (oc == null) {
+// oc = DirectoryServer.getDefaultObjectClass(name);
+// }
+// return Entries.containsObjectClass(entry, oc);
+ return entry.containsAttribute("objectClass", oc);
}
}
@@ -347,28 +356,22 @@
private static final Logger debugLogger = LoggerFactory.getLogger(ServerManagementContext.class);
- /** The singleton instance. **/
- private final static ServerManagementContext INSTANCE = new ServerManagementContext();
-
/**
- * The root server managed object.
+ * The root server managed object, lazily initialized.
*/
- private static final ServerManagedObject<RootCfg> ROOT = new ServerManagedObject<RootCfg>(
- ManagedObjectPath.emptyPath(), RootCfgDefn.getInstance(),
- Collections.<PropertyDefinition<?>, SortedSet<?>> emptyMap(), null);
+ private volatile ServerManagedObject<RootCfg> root;
+
+ /** Repository of configuration entries */
+ private final ConfigurationRepository configRepository;
/**
- * Get the single server-side management context.
+ * Creates a context from the provided configuration repository.
*
- * @return Returns the single server-side management context.
+ * @param repository
+ * The repository of configuration entries.
*/
- public static ServerManagementContext getInstance() {
- return INSTANCE;
- }
-
- // Private constructor.
- private ServerManagementContext() {
- // No implementation required.
+ ServerManagementContext(ConfigurationRepository repository) {
+ configRepository = repository;
}
/**
@@ -397,7 +400,7 @@
// Get the configuration entry.
DN targetDN = DNBuilder.create(path);
- ConfigEntry configEntry = getManagedObjectConfigEntry(targetDN);
+ Entry configEntry = getManagedObjectConfigEntry(targetDN);
try {
ServerManagedObject<? extends S> managedObject;
managedObject = decode(path, configEntry);
@@ -496,7 +499,7 @@
// Determine the exact type of managed object referenced by the
// path.
DN dn = DNBuilder.create(path);
- ConfigEntry configEntry = getManagedObjectConfigEntry(dn);
+ Entry configEntry = getManagedObjectConfigEntry(dn);
DefinitionResolver resolver = new MyDefinitionResolver(configEntry);
ManagedObjectDefinition<? extends C, ? extends S> managedObjDef;
@@ -520,7 +523,7 @@
* Get the root configuration manager associated with this management
* context.
*
- * @return Returns the root configuration manager associated with this
+ * @return the root configuration manager associated with this
* management context.
*/
public RootCfg getRootConfiguration() {
@@ -531,11 +534,22 @@
* Get the root configuration server managed object associated with this
* management context.
*
- * @return Returns the root configuration server managed object associated
- * with this management context.
+ * @return the root configuration server managed object
*/
public ServerManagedObject<RootCfg> getRootConfigurationManagedObject() {
- return ROOT;
+ // Use lazy initialisation because it needs a reference to this server context.
+ ServerManagedObject<RootCfg> rootObject = root;
+ if (rootObject == null) {
+ synchronized(this) {
+ rootObject = root;
+ if (rootObject == null) {
+ root = rootObject = new ServerManagedObject<RootCfg>(ManagedObjectPath.emptyPath(),
+ RootCfgDefn.getInstance(), Collections.<PropertyDefinition<?>, SortedSet<?>> emptyMap(),
+ null, this);
+ }
+ }
+ }
+ return rootObject;
}
/**
@@ -562,19 +576,12 @@
// Get the target entry.
DN targetDN = DNBuilder.create(parent, relationDef);
- ConfigEntry configEntry;
+ Set<DN> children;
try {
- configEntry = DirectoryServer.getConfigEntry(targetDN);
+ children = configRepository.getChildren(targetDN);
} catch (ConfigException e) {
return new String[0];
}
-
- if (configEntry == null) {
- return new String[0];
- }
-
- // Retrieve the children.
- Set<DN> children = configEntry.getChildren();
List<String> names = new ArrayList<String>(children.size());
for (DN child : children) {
// Assume that RDNs are single-valued and can be trimmed.
@@ -627,7 +634,7 @@
* be decoded.
*/
<C extends ConfigurationClient, S extends Configuration> ServerManagedObject<? extends S> decode(
- ManagedObjectPath<C, S> path, ConfigEntry configEntry) throws DefinitionDecodingException,
+ ManagedObjectPath<C, S> path, Entry configEntry) throws DefinitionDecodingException,
ServerManagedObjectDecodingException {
return decode(path, configEntry, null);
}
@@ -659,7 +666,7 @@
* be decoded.
*/
<C extends ConfigurationClient, S extends Configuration> ServerManagedObject<? extends S> decode(
- ManagedObjectPath<C, S> path, ConfigEntry configEntry, ConfigEntry newConfigEntry)
+ ManagedObjectPath<C, S> path, Entry configEntry, Entry 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
@@ -683,25 +690,25 @@
// If there were no decoding problems then return the managed
// object, otherwise throw an operations exception.
- ServerManagedObject<? extends S> mo = decodeAux(path, mod, properties, configEntry);
+ ServerManagedObject<? extends S> managedObject = decodeAux(path, mod, properties, configEntry.getName());
if (exceptions.isEmpty()) {
- return mo;
+ return managedObject;
} else {
- throw new ServerManagedObjectDecodingException(mo, exceptions);
+ throw new ServerManagedObjectDecodingException(managedObject, exceptions);
}
}
// Decode helper method required to avoid generics warning.
private <C extends ConfigurationClient, S extends Configuration> ServerManagedObject<S> decodeAux(
ManagedObjectPath<? super C, ? super S> path, ManagedObjectDefinition<C, S> d,
- Map<PropertyDefinition<?>, SortedSet<?>> properties, ConfigEntry configEntry) {
+ Map<PropertyDefinition<?>, SortedSet<?>> properties, DN configDN) {
ManagedObjectPath<C, S> newPath = path.asSubType(d);
- return new ServerManagedObject<S>(newPath, d, properties, configEntry);
+ return new ServerManagedObject<S>(newPath, d, properties, configDN, this);
}
// Create a property using the provided string values.
private <T> SortedSet<T> decodeProperty(ManagedObjectPath<?, ?> path, PropertyDefinition<T> propertyDef,
- Iterable<Attribute> attributes, ConfigEntry newConfigEntry) throws PropertyException {
+ Iterable<Attribute> attributes, Entry newConfigEntry) throws PropertyException {
PropertyException exception = null;
SortedSet<T> pvalues = new TreeSet<T>(propertyDef);
@@ -748,28 +755,50 @@
// Gets the attribute associated with a property from a ConfigEntry.
private Iterable<Attribute> getAttribute(ManagedObjectDefinition<?, ?> d, PropertyDefinition<?> pd,
- ConfigEntry configEntry) {
+ Entry configEntry) {
// TODO: we create a default attribute type if it is
// undefined. We should log a warning here if this is the case
// since the attribute should have been defined.
String attrID = LDAPProfile.getInstance().getAttributeName(d, pd);
AttributeType type = DirectoryServer.getAttributeType(attrID, true);
- return configEntry.getEntry().getAllAttributes(AttributeDescription.create(type));
+ return configEntry.getAllAttributes(AttributeDescription.create(type));
}
// Get the default values for the specified property.
private <T> Collection<T> getDefaultValues(ManagedObjectPath<?, ?> p, PropertyDefinition<T> pd,
- ConfigEntry newConfigEntry) throws DefaultBehaviorException {
+ Entry newConfigEntry) throws DefaultBehaviorException {
DefaultValueFinder<T> v = new DefaultValueFinder<T>(newConfigEntry);
return v.find(p, pd);
}
+ /**
+ * Retrieves a configuration entry corresponding to the provided DN.
+ *
+ * @param dn
+ * DN of the configuration entry.
+ * @return the configuration entry
+ * @throws ConfigException
+ * If a problem occurs.
+ */
+ public Entry getConfigEntry(DN dn) throws ConfigException {
+ return configRepository.getEntry(dn);
+ }
+
+ /**
+ * Returns the repository containing all configuration entries.
+ *
+ * @return the repository
+ */
+ public ConfigurationRepository getConfigRepository() {
+ return configRepository;
+ }
+
// Gets a config entry required for a managed object and throws a
// config exception on failure.
- private ConfigEntry getManagedObjectConfigEntry(DN dn) throws ConfigException {
- ConfigEntry configEntry;
+ private Entry getManagedObjectConfigEntry(DN dn) throws ConfigException {
+ Entry configEntry;
try {
- configEntry = DirectoryServer.getConfigEntry(dn);
+ configEntry = configRepository.getEntry(dn);
} catch (ConfigException e) {
debugLogger.trace("Unable to perform post add", e);
diff --git a/opendj-sdk/opendj-admin/src/main/java/org/opends/server/api/ConfigAddListener.java b/opendj-sdk/opendj-admin/src/main/java/org/opends/server/api/ConfigAddListener.java
index 2f9719e..d73b357 100644
--- a/opendj-sdk/opendj-admin/src/main/java/org/opends/server/api/ConfigAddListener.java
+++ b/opendj-sdk/opendj-admin/src/main/java/org/opends/server/api/ConfigAddListener.java
@@ -26,7 +26,7 @@
package org.opends.server.api;
import org.forgerock.i18n.LocalizableMessageBuilder;
-import org.opends.server.config.ConfigEntry;
+import org.forgerock.opendj.ldap.Entry;
import org.opends.server.types.ConfigChangeResult;
/**
@@ -48,7 +48,7 @@
* @return {@code true} if the proposed entry contains an acceptable
* configuration, or {@code false} if it does not.
*/
- public boolean configAddIsAcceptable(ConfigEntry configEntry, LocalizableMessageBuilder unacceptableReason);
+ public boolean configAddIsAcceptable(Entry configEntry, LocalizableMessageBuilder unacceptableReason);
/**
* Attempts to apply a new configuration based on the provided added entry.
@@ -59,5 +59,5 @@
* @return Information about the result of processing the configuration
* change.
*/
- public ConfigChangeResult applyConfigurationAdd(ConfigEntry configEntry);
+ public ConfigChangeResult applyConfigurationAdd(Entry configEntry);
}
diff --git a/opendj-sdk/opendj-admin/src/main/java/org/opends/server/api/ConfigChangeListener.java b/opendj-sdk/opendj-admin/src/main/java/org/opends/server/api/ConfigChangeListener.java
index 0a67389..d84f0d7 100644
--- a/opendj-sdk/opendj-admin/src/main/java/org/opends/server/api/ConfigChangeListener.java
+++ b/opendj-sdk/opendj-admin/src/main/java/org/opends/server/api/ConfigChangeListener.java
@@ -25,9 +25,9 @@
*/
package org.opends.server.api;
-import org.opends.server.config.ConfigEntry;
import org.opends.server.types.ConfigChangeResult;
import org.forgerock.i18n.LocalizableMessageBuilder;
+import org.forgerock.opendj.ldap.Entry;
/**
* This interface defines the methods that a Directory Server component should
@@ -48,7 +48,7 @@
* @return {@code true} if the proposed entry contains an acceptable
* configuration, or {@code false} if it does not.
*/
- public boolean configChangeIsAcceptable(ConfigEntry configEntry, LocalizableMessageBuilder unacceptableReason);
+ public boolean configChangeIsAcceptable(Entry configEntry, LocalizableMessageBuilder unacceptableReason);
/**
* Attempts to apply a new configuration to this Directory Server component
@@ -60,5 +60,5 @@
* @return Information about the result of processing the configuration
* change.
*/
- public ConfigChangeResult applyConfigurationChange(ConfigEntry configEntry);
+ public ConfigChangeResult applyConfigurationChange(Entry configEntry);
}
diff --git a/opendj-sdk/opendj-admin/src/main/java/org/opends/server/api/ConfigDeleteListener.java b/opendj-sdk/opendj-admin/src/main/java/org/opends/server/api/ConfigDeleteListener.java
index b413f39..a68d098 100644
--- a/opendj-sdk/opendj-admin/src/main/java/org/opends/server/api/ConfigDeleteListener.java
+++ b/opendj-sdk/opendj-admin/src/main/java/org/opends/server/api/ConfigDeleteListener.java
@@ -25,50 +25,39 @@
*/
package org.opends.server.api;
-
-
-import org.opends.server.config.ConfigEntry;
import org.opends.server.types.ConfigChangeResult;
import org.forgerock.i18n.LocalizableMessageBuilder;
-
+import org.forgerock.opendj.ldap.Entry;
/**
- * This interface defines the methods that a Directory Server
- * component should implement if it wishes to be able to receive
- * notification if entries below a configuration entry are removed.
+ * This interface defines the methods that a Directory Server component should
+ * implement if it wishes to be able to receive notification if entries below a
+ * configuration entry are removed.
*/
-public interface ConfigDeleteListener
-{
- /**
- * Indicates whether it is acceptable to remove the provided
- * configuration entry.
- *
- * @param configEntry The configuration entry that will be
- * removed from the configuration.
- * @param unacceptableReason A buffer to which this method can
- * append a human-readable message
- * explaining why the proposed delete is
- * not acceptable.
- *
- * @return {@code true} if the proposed entry may be removed from
- * the configuration, or {@code false} if not.
- */
- public boolean configDeleteIsAcceptable(ConfigEntry configEntry,
- LocalizableMessageBuilder unacceptableReason);
+public interface ConfigDeleteListener {
+ /**
+ * Indicates whether it is acceptable to remove the provided configuration
+ * entry.
+ *
+ * @param configEntry
+ * The configuration entry that will be removed from the
+ * configuration.
+ * @param unacceptableReason
+ * A buffer to which this method can append a human-readable
+ * message explaining why the proposed delete is not acceptable.
+ * @return {@code true} if the proposed entry may be removed from the
+ * configuration, or {@code false} if not.
+ */
+ public boolean configDeleteIsAcceptable(Entry configEntry, LocalizableMessageBuilder unacceptableReason);
-
-
- /**
- * Attempts to apply a new configuration based on the provided
- * deleted entry.
- *
- * @param configEntry The new configuration entry that has been
- * deleted.
- *
- * @return Information about the result of processing the
- * configuration change.
- */
- public ConfigChangeResult applyConfigurationDelete(
- ConfigEntry configEntry);
+ /**
+ * Attempts to apply a new configuration based on the provided deleted
+ * entry.
+ *
+ * @param configEntry
+ * The new configuration entry that has been deleted.
+ * @return Information about the result of processing the configuration
+ * change.
+ */
+ public ConfigChangeResult applyConfigurationDelete(Entry configEntry);
}
-
diff --git a/opendj-sdk/opendj-admin/src/main/java/org/opends/server/config/ConfigEntry.java b/opendj-sdk/opendj-admin/src/main/java/org/opends/server/config/ConfigEntry.java
deleted file mode 100644
index 89db1b5..0000000
--- a/opendj-sdk/opendj-admin/src/main/java/org/opends/server/config/ConfigEntry.java
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * 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 legal-notices/CDDLv1_0.txt
- * or http://forgerock.org/license/CDDLv1.0.html.
- * 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 legal-notices/CDDLv1_0.txt.
- * 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
- *
- *
- * Copyright 2006-2008 Sun Microsystems, Inc.
- */
-package org.opends.server.config;
-
-import java.util.Set;
-import java.util.concurrent.CopyOnWriteArrayList;
-
-import org.forgerock.opendj.ldap.DN;
-import org.forgerock.opendj.ldap.Entries;
-import org.forgerock.opendj.ldap.Entry;
-import org.forgerock.opendj.ldap.schema.ObjectClass;
-import org.opends.server.api.ConfigAddListener;
-import org.opends.server.api.ConfigChangeListener;
-import org.opends.server.api.ConfigDeleteListener;
-import org.opends.server.core.DirectoryServer;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * A config entry wraps an entry to provides add, change and delete listeners on
- * it.
- */
-public final class ConfigEntry {
-
- private static final Logger debugLogger = LoggerFactory.getLogger(ConfigEntry.class);
-
- /** The set of add listeners that have been registered with this entry. */
- private final CopyOnWriteArrayList<ConfigAddListener> addListeners;
-
- /** The set of change listeners that have been registered with this entry. */
- private final CopyOnWriteArrayList<ConfigChangeListener> changeListeners;
-
- /** The set of delete listeners that have been registered with this entry. */
- private final CopyOnWriteArrayList<ConfigDeleteListener> deleteListeners;
-
- /** The actual entry wrapped by this configuration entry. */
- private Entry entry;
-
- private final ConfigurationRepository configRepository;
-
- /**
- * Creates a new config entry with the provided entry.
- *
- * @param entry
- * The entry that will be encapsulated by this config entry.
- */
- public ConfigEntry(Entry entry, ConfigurationRepository configRepository) {
- this.entry = entry;
- this.configRepository = configRepository;
- addListeners = new CopyOnWriteArrayList<ConfigAddListener>();
- changeListeners = new CopyOnWriteArrayList<ConfigChangeListener>();
- deleteListeners = new CopyOnWriteArrayList<ConfigDeleteListener>();
- }
-
- /**
- * Retrieves the actual entry wrapped by this configuration entry.
- *
- * @return The actual entry wrapped by this configuration entry.
- */
- public Entry getEntry() {
- return entry;
- }
-
- /**
- * Retrieves the DN for this configuration entry.
- *
- * @return The DN for this configuration entry.
- */
- public DN getDN() {
- return entry.getName();
- }
-
- /**
- * Indicates whether this configuration entry contains the specified
- * objectclass.
- *
- * @param name
- * The name of the objectclass for which to make the
- * determination.
- * @return <CODE>true</CODE> if this configuration entry contains the
- * specified objectclass, or <CODE>false</CODE> if not.
- */
- public boolean hasObjectClass(String name) {
- // TODO : use the schema to get object class and check it in the entry
- ObjectClass oc = DirectoryServer.getObjectClass(name.toLowerCase());
- if (oc == null) {
- oc = DirectoryServer.getDefaultObjectClass(name);
- }
-
- return Entries.containsObjectClass(entry, oc);
- }
-
- /**
- * Retrieves the set of change listeners that have been registered with this
- * configuration entry.
- *
- * @return The set of change listeners that have been registered with this
- * configuration entry.
- */
- public CopyOnWriteArrayList<ConfigChangeListener> getChangeListeners() {
- return changeListeners;
- }
-
- /**
- * Registers the provided change listener so that it will be notified of any
- * changes to this configuration entry. No check will be made to determine
- * whether the provided listener is already registered.
- *
- * @param listener
- * The change listener to register with this config entry.
- */
- public void registerChangeListener(ConfigChangeListener listener) {
- changeListeners.add(listener);
- }
-
- /**
- * Attempts to deregister the provided change listener with this
- * configuration entry.
- *
- * @param listener
- * The change listener to deregister with this config entry.
- * @return <CODE>true</CODE> if the specified listener was deregistered, or
- * <CODE>false</CODE> if it was not.
- */
- public boolean deregisterChangeListener(ConfigChangeListener listener) {
- return changeListeners.remove(listener);
- }
-
- /**
- * Retrieves the set of config add listeners that have been registered for
- * this entry.
- *
- * @return The set of config add listeners that have been registered for
- * this entry.
- */
- public CopyOnWriteArrayList<ConfigAddListener> getAddListeners() {
- return addListeners;
- }
-
- /**
- * Registers the provided add listener so that it will be notified if any
- * new entries are added immediately below this configuration entry.
- *
- * @param listener
- * The add listener that should be registered.
- */
- public void registerAddListener(ConfigAddListener listener) {
- addListeners.addIfAbsent(listener);
- }
-
- /**
- * Deregisters the provided add listener so that it will no longer be
- * notified if any new entries are added immediately below this
- * configuration entry.
- *
- * @param listener
- * The add listener that should be deregistered.
- */
- public void deregisterAddListener(ConfigAddListener listener) {
- addListeners.remove(listener);
- }
-
- /**
- * Retrieves the set of config delete listeners that have been registered
- * for this entry.
- *
- * @return The set of config delete listeners that have been registered for
- * this entry.
- */
- public CopyOnWriteArrayList<ConfigDeleteListener> getDeleteListeners() {
- return deleteListeners;
- }
-
- /**
- * Registers the provided delete listener so that it will be notified if any
- * entries are deleted immediately below this configuration entry.
- *
- * @param listener
- * The delete listener that should be registered.
- */
- public void registerDeleteListener(ConfigDeleteListener listener) {
- deleteListeners.addIfAbsent(listener);
- }
-
- /**
- * Deregisters the provided delete listener so that it will no longer be
- * notified if any new are removed immediately below this configuration
- * entry.
- *
- * @param listener
- * The delete listener that should be deregistered.
- */
- public void deregisterDeleteListener(ConfigDeleteListener listener) {
- deleteListeners.remove(listener);
- }
-
- /** {@inheritDoc} */
- @Override
- public String toString() {
- return entry.getName().toNormalizedString();
- }
-
- /**
- * Retrieves the set of children associated with this configuration entry.
- *
- * @return The set of children associated with this configuration entry.
- */
- public Set<DN> getChildren() {
- return configRepository.getChildren(entry);
- }
-}
diff --git a/opendj-sdk/opendj-admin/src/main/java/org/opends/server/config/ConfigurationRepository.java b/opendj-sdk/opendj-admin/src/main/java/org/opends/server/config/ConfigurationRepository.java
index f6eb5cd..801ad01 100644
--- a/opendj-sdk/opendj-admin/src/main/java/org/opends/server/config/ConfigurationRepository.java
+++ b/opendj-sdk/opendj-admin/src/main/java/org/opends/server/config/ConfigurationRepository.java
@@ -25,23 +25,155 @@
*/
package org.opends.server.config;
+import java.util.List;
import java.util.Set;
-
import org.forgerock.opendj.ldap.DN;
import org.forgerock.opendj.ldap.Entry;
+import org.opends.server.api.ConfigAddListener;
+import org.opends.server.api.ConfigChangeListener;
+import org.opends.server.api.ConfigDeleteListener;
/**
- * Provides the configuration elements.
+ * Provides configuration entries and listener registration on the entries.
*/
public interface ConfigurationRepository {
/**
- * Returns the set of children of the provided entry.
+ * Returns the set of DNs of children of the entry corresponding to the
+ * provided DN. .
*
- * @param entry
- * The configuration entry.
- * @return the set of children of the entry
+ * @param dn
+ * DN of a configuration entry.
+ * @return the set of DN of children of the corresponding entry
+ * @throws ConfigException
+ * If a problem occurs during retrieval.
*/
- Set<DN> getChildren(Entry entry);
+ Set<DN> getChildren(DN dn) throws ConfigException;
+
+ /**
+ * Returns the configuration entry for the provided DN.
+ *
+ * @param dn
+ * DN of the configuration entry
+ * @return the config entry
+ * @throws ConfigException
+ * If a problem occurs while trying to retrieve the requested
+ * entry.
+ */
+ Entry getEntry(DN dn) throws ConfigException;
+
+ /**
+ * Checks if the provided DN corresponds to a configuration entry.
+ *
+ * @param dn
+ * DN of the configuration entry
+ * @return {@code true} if and only if there is a configuration entry with
+ * this DN
+ * @throws ConfigException
+ * If a problem occurs.
+ */
+ boolean hasEntry(DN dn) throws ConfigException;
+
+ /**
+ * Registers the provided add listener so that it will be notified if any
+ * new entries are added immediately below the entry corresponding to the
+ * provided DN.
+ *
+ * @param dn
+ * The DN of the configuration entry.
+ * @param listener
+ * The add listener that should be registered.
+ */
+ public void registerAddListener(DN dn, ConfigAddListener listener);
+
+ /**
+ * Registers the provided delete listener so that it will be notified if any
+ * entries are deleted immediately below the entry corresponding to the
+ * provided DN.
+ *
+ * @param dn
+ * The DN of the configuration entry.
+ * @param listener
+ * The delete listener that should be registered.
+ */
+ public void registerDeleteListener(DN dn, ConfigDeleteListener listener);
+
+ /**
+ * Registers the provided change listener so that it will be notified of any
+ * changes to the entry corrresponding to provided DN. No check will be made
+ * to determine whether the provided listener is already registered.
+ *
+ * @param dn
+ * The DN of the configuration entry.
+ * @param listener
+ * The change listener that should be registered.
+ */
+ public void registerChangeListener(DN dn, ConfigChangeListener listener);
+
+ /**
+ * Deregisters the provided add listener so that it will no longer be
+ * notified if any new entries are added immediately below the entry
+ * corresponding to the provided DN.
+ *
+ * @param dn
+ * The DN of the configuration entry.
+ * @param listener
+ * The add listener that should be deregistered.
+ */
+ public void deregisterAddListener(DN dn, ConfigAddListener listener);
+
+ /**
+ * Deregisters the provided delete listener so that it will no longer be
+ * notified if any entries are deleted immediately below the entry
+ * corresponding to the provided DN.
+ *
+ * @param dn
+ * The DN of the configuration entry.
+ * @param listener
+ * The delete listener that should be deregistered.
+ */
+ public void deregisterDeleteListener(DN dn, ConfigDeleteListener listener);
+
+ /**
+ * Attempts to deregister the provided change listener with the provided DN.
+ *
+ * @param dn
+ * The DN of the configuration entry.
+ * @param listener
+ * The change listener to deregister with this DN.
+ * @return <CODE>true</CODE> if the specified listener was deregistered, or
+ * <CODE>false</CODE> if it was not.
+ */
+ public boolean deregisterChangeListener(DN dn, ConfigChangeListener listener);
+
+ /**
+ * Retrieves the add listeners that have been registered with the provided
+ * DN.
+ *
+ * @param dn
+ * The DN of the configuration entry.
+ * @return The list of add listeners.
+ */
+ public List<ConfigAddListener> getAddListeners(DN dn);
+
+ /**
+ * Retrieves the delete listeners that have been registered with the
+ * provided DN.
+ *
+ * @param dn
+ * The DN of the configuration entry.
+ * @return The list of delete listeners.
+ */
+ public List<ConfigDeleteListener> getDeleteListeners(DN dn);
+
+ /**
+ * Retrieves the change listeners that have been registered with the
+ * provided DN.
+ *
+ * @param dn
+ * The DN of the configuration entry.
+ * @return The list of change listeners.
+ */
+ public List<ConfigChangeListener> getChangeListeners(DN dn);
}
diff --git a/opendj-sdk/opendj-admin/src/main/java/org/opends/server/core/DirectoryServer.java b/opendj-sdk/opendj-admin/src/main/java/org/opends/server/core/DirectoryServer.java
index 0e97bc7..002a9fa 100644
--- a/opendj-sdk/opendj-admin/src/main/java/org/opends/server/core/DirectoryServer.java
+++ b/opendj-sdk/opendj-admin/src/main/java/org/opends/server/core/DirectoryServer.java
@@ -25,13 +25,10 @@
*/
package org.opends.server.core;
-import org.forgerock.opendj.ldap.DN;
import org.forgerock.opendj.ldap.schema.AttributeType;
import org.forgerock.opendj.ldap.schema.ObjectClass;
import org.forgerock.opendj.ldap.schema.Schema;
import org.forgerock.opendj.ldap.schema.UnknownSchemaElementException;
-import org.opends.server.config.ConfigEntry;
-import org.opends.server.config.ConfigException;
/**
* TODO : this is a stub, with some default implementations for some methods,
@@ -116,8 +113,4 @@
return getObjectClass(name);
}
- public static ConfigEntry getConfigEntry(DN dn) throws ConfigException {
- throw new RuntimeException("Not implemented");
- }
-
}
diff --git a/opendj-sdk/opendj-admin/src/test/java/org/opends/server/admin/server/AdminTestCaseUtils.java b/opendj-sdk/opendj-admin/src/test/java/org/opends/server/admin/server/AdminTestCaseUtils.java
new file mode 100644
index 0000000..e6cf3aa
--- /dev/null
+++ b/opendj-sdk/opendj-admin/src/test/java/org/opends/server/admin/server/AdminTestCaseUtils.java
@@ -0,0 +1,117 @@
+/*
+ * 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 legal-notices/CDDLv1_0.txt
+ * or http://forgerock.org/license/CDDLv1.0.html.
+ * 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 legal-notices/CDDLv1_0.txt.
+ * 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
+ *
+ *
+ * Copyright 2008 Sun Microsystems, Inc.
+ */
+package org.opends.server.admin.server;
+
+import org.forgerock.opendj.admin.meta.RootCfgDefn;
+import org.forgerock.opendj.ldap.Entry;
+import org.opends.server.admin.AbstractManagedObjectDefinition;
+import org.opends.server.admin.Configuration;
+import org.opends.server.admin.ConfigurationClient;
+import org.opends.server.admin.DefinitionDecodingException;
+import org.opends.server.admin.LDAPProfile;
+import org.opends.server.admin.ManagedObjectPath;
+import org.opends.server.admin.RelationDefinition;
+import org.opends.server.admin.SingletonRelationDefinition;
+import org.opends.server.config.ConfigException;
+
+/**
+ * This class defines some utility functions which can be used by test cases
+ * which interact with the admin framework.
+ */
+public final class AdminTestCaseUtils {
+
+ // The relation name which will be used for dummy configurations. A
+ // deliberately obfuscated name is chosen to avoid clashes.
+ private static final String DUMMY_TEST_RELATION = "*dummy*test*relation*";
+
+ // Indicates if the dummy relation profile has been registered.
+ private static boolean isProfileRegistered = false;
+
+ // Prevent instantiation.
+ private AdminTestCaseUtils() {
+ // No implementation required.
+ }
+
+ /**
+ * Decodes a configuration entry into the required type of server
+ * configuration.
+ *
+ * @param <S>
+ * The type of server configuration to be decoded.
+ * @param definition
+ * The required definition of the required managed object.
+ * @param entry
+ * An entry containing the configuration to be decoded.
+ * @return Returns the new server-side configuration.
+ * @throws ConfigException
+ * If the entry could not be decoded.
+ */
+ public static <S extends Configuration> S getConfiguration(ServerManagementContext context,
+ AbstractManagedObjectDefinition<?, S> definition, Entry entry) throws ConfigException {
+ try {
+ ServerManagedObject<? extends S> mo = context.decode(getPath(definition), entry);
+
+ // Ensure constraints are satisfied.
+ mo.ensureIsUsable();
+
+ return mo.getConfiguration();
+ } catch (DefinitionDecodingException e) {
+ throw ConfigExceptionFactory.getInstance().createDecodingExceptionAdaptor(entry.getName(), e);
+ } catch (ServerManagedObjectDecodingException e) {
+ throw ConfigExceptionFactory.getInstance().createDecodingExceptionAdaptor(e);
+ } catch (ConstraintViolationException e) {
+ throw ConfigExceptionFactory.getInstance().createDecodingExceptionAdaptor(e);
+ }
+ }
+
+ // Construct a dummy path.
+ private synchronized static <C extends ConfigurationClient, S extends Configuration> ManagedObjectPath<C, S> getPath(
+ AbstractManagedObjectDefinition<C, S> d) {
+ if (!isProfileRegistered) {
+ LDAPProfile.Wrapper profile = new LDAPProfile.Wrapper() {
+
+ @Override
+ public String getRelationRDNSequence(RelationDefinition<?, ?> r) {
+ if (r.getName().equals(DUMMY_TEST_RELATION)) {
+ return "cn=dummy configuration,cn=config";
+ } else {
+ return null;
+ }
+ }
+
+ };
+
+ LDAPProfile.getInstance().pushWrapper(profile);
+ isProfileRegistered = true;
+ }
+
+ SingletonRelationDefinition.Builder<C, S> builder = new SingletonRelationDefinition.Builder<C, S>(
+ RootCfgDefn.getInstance(), DUMMY_TEST_RELATION, d);
+ ManagedObjectPath<?, ?> root = ManagedObjectPath.emptyPath();
+ return root.child(builder.getInstance());
+
+ }
+}
diff --git a/opendj-sdk/opendj-admin/src/test/java/org/opends/server/admin/server/AggregationServerTest.java b/opendj-sdk/opendj-admin/src/test/java/org/opends/server/admin/server/AggregationServerTest.java
new file mode 100644
index 0000000..c351849
--- /dev/null
+++ b/opendj-sdk/opendj-admin/src/test/java/org/opends/server/admin/server/AggregationServerTest.java
@@ -0,0 +1,814 @@
+/*
+ * 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 legal-notices/CDDLv1_0.txt
+ * or http://forgerock.org/license/CDDLv1.0.html.
+ * 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 legal-notices/CDDLv1_0.txt.
+ * 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
+ *
+ *
+ * Copyright 2007-2008 Sun Microsystems, Inc.
+ * Portions copyright 2013 ForgeRock AS
+ */
+package org.opends.server.admin.server;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import javax.naming.ldap.LdapName;
+
+import org.forgerock.i18n.LocalizableMessage;
+import org.forgerock.opendj.admin.client.ConnectionHandlerCfgClient;
+import org.forgerock.opendj.admin.client.LDAPConnectionHandlerCfgClient;
+import org.forgerock.opendj.admin.client.RootCfgClient;
+import org.forgerock.opendj.admin.meta.LDAPConnectionHandlerCfgDefn;
+import org.forgerock.opendj.admin.server.ConnectionHandlerCfg;
+import org.forgerock.opendj.admin.server.RootCfg;
+import org.forgerock.opendj.ldap.ResultCode;
+import org.forgerock.opendj.ldap.TestCaseUtils;
+import org.opends.server.admin.AdminTestCase;
+import org.opends.server.admin.AdministratorAction;
+import org.opends.server.admin.AggregationPropertyDefinition;
+import org.opends.server.admin.IllegalPropertyValueStringException;
+import org.opends.server.admin.ManagedObjectNotFoundException;
+import org.opends.server.admin.PropertyException;
+import org.opends.server.admin.PropertyOption;
+import org.opends.server.admin.TestCfg;
+import org.opends.server.admin.TestChildCfg;
+import org.opends.server.admin.TestChildCfgDefn;
+import org.opends.server.admin.TestParentCfg;
+import org.opends.server.admin.UndefinedDefaultBehaviorProvider;
+import org.opends.server.admin.client.OperationRejectedException;
+import org.opends.server.admin.condition.Conditions;
+import org.opends.server.config.ConfigException;
+import org.opends.server.core.DirectoryServer;
+import org.opends.server.types.ConfigChangeResult;
+import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+/**
+ * Test cases for aggregations on the server-side.
+ */
+@Test(singleThreaded = true)
+public final class AggregationServerTest extends AdminTestCase {
+
+ /**
+ * Dummy change listener for triggering change constraint call-backs.
+ */
+ private static final class DummyChangeListener implements ConfigurationChangeListener<TestChildCfg> {
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public ConfigChangeResult applyConfigurationChange(TestChildCfg configuration) {
+ return new ConfigChangeResult(ResultCode.SUCCESS, false);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isConfigurationChangeAcceptable(TestChildCfg configuration, List<LocalizableMessage> unacceptableReasons) {
+ return true;
+ }
+ }
+
+ /**
+ * Dummy delete listener for triggering delete constraint call-backs.
+ */
+ private static final class DummyDeleteListener implements ConfigurationDeleteListener<TestChildCfg> {
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public ConfigChangeResult applyConfigurationDelete(TestChildCfg configuration) {
+ return new ConfigChangeResult(ResultCode.SUCCESS, false);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isConfigurationDeleteAcceptable(TestChildCfg configuration, List<LocalizableMessage> unacceptableReasons) {
+ return true;
+ }
+ }
+
+ private static final String TEST_CHILD_7_DN = "cn=test child 7,cn=test children,cn=test parent 1,cn=test parents,cn=config";
+
+ private static final String TEST_CHILD_6_DN = "cn=test child 6,cn=test children,cn=test parent 1,cn=test parents,cn=config";
+
+ /** The name of the test connection handler. */
+ private static final String TEST_CONNECTION_HANDLER_NAME = "Test Connection Handler";
+
+ /** Test child 1 LDIF. */
+ private static final String[] TEST_CHILD_1 = new String[] {
+ "dn: cn=test child 1,cn=test children,cn=test parent 1,cn=test parents,cn=config", "objectclass: top",
+ "objectclass: ds-cfg-test-child-dummy", "cn: test child 1", "ds-cfg-enabled: true",
+ "ds-cfg-java-class: org.opends.server.extensions.UserDefinedVirtualAttributeProvider",
+ "ds-cfg-attribute-type: description", "ds-cfg-conflict-behavior: virtual-overrides-real" };
+
+ /** Test child 2 LDIF. */
+ private static final String[] TEST_CHILD_2 = new String[] {
+ "dn: cn=test child 2,cn=test children,cn=test parent 1,cn=test parents,cn=config", "objectclass: top",
+ "objectclass: ds-cfg-test-child-dummy", "cn: test child 2", "ds-cfg-enabled: true",
+ "ds-cfg-java-class: org.opends.server.extensions.UserDefinedVirtualAttributeProvider",
+ "ds-cfg-attribute-type: description", "ds-cfg-conflict-behavior: virtual-overrides-real",
+ "ds-cfg-rotation-policy: cn=LDAP Connection Handler, cn=connection handlers, cn=config" };
+
+ /** Test child 3 LDIF (invalid reference). */
+ private static final String[] TEST_CHILD_3 = new String[] {
+ "dn: cn=test child 3,cn=test children,cn=test parent 1,cn=test parents,cn=config", "objectclass: top",
+ "objectclass: ds-cfg-test-child-dummy", "cn: test child 3", "ds-cfg-enabled: true",
+ "ds-cfg-java-class: org.opends.server.extensions.UserDefinedVirtualAttributeProvider",
+ "ds-cfg-attribute-type: description", "ds-cfg-conflict-behavior: virtual-overrides-real",
+ "ds-cfg-rotation-policy: cn=LDAP Connection Handler, cn=bad rdn, cn=config" };
+
+ /** Test child 4 LDIF. */
+ private static final String[] TEST_CHILD_4 = new String[] {
+ "dn: cn=test child 4,cn=test children,cn=test parent 1,cn=test parents,cn=config", "objectclass: top",
+ "objectclass: ds-cfg-test-child-dummy", "cn: test child 4", "ds-cfg-enabled: true",
+ "ds-cfg-java-class: org.opends.server.extensions.UserDefinedVirtualAttributeProvider",
+ "ds-cfg-attribute-type: description", "ds-cfg-conflict-behavior: virtual-overrides-real",
+ "ds-cfg-rotation-policy: cn=LDAP Connection Handler, cn=connection handlers, cn=config",
+ "ds-cfg-rotation-policy: cn=LDAPS Connection Handler, cn=connection handlers, cn=config" };
+
+ /** Test child 5 LDIF. */
+ private static final String[] TEST_CHILD_5 = new String[] {
+ "dn: cn=test child 5,cn=test children,cn=test parent 1,cn=test parents,cn=config", "objectclass: top",
+ "objectclass: ds-cfg-test-child-dummy", "cn: test child 5", "ds-cfg-enabled: true",
+ "ds-cfg-java-class: org.opends.server.extensions.UserDefinedVirtualAttributeProvider",
+ "ds-cfg-attribute-type: description", "ds-cfg-conflict-behavior: virtual-overrides-real",
+ "ds-cfg-rotation-policy: cn=BAD Connection Handler 1, cn=connection handlers, cn=config",
+ "ds-cfg-rotation-policy: cn=BAD Connection Handler 2, cn=connection handlers, cn=config",
+ "ds-cfg-rotation-policy: cn=LDAP Connection Handler, cn=connection handlers, cn=config" };
+
+ /** Test child 6 LDIF. */
+ private static final String[] TEST_CHILD_6 = new String[] {
+ "dn: cn=test child 6,cn=test children,cn=test parent 1,cn=test parents,cn=config", "objectclass: top",
+ "objectclass: ds-cfg-test-child-dummy", "cn: test child 6", "ds-cfg-enabled: true",
+ "ds-cfg-java-class: org.opends.server.extensions.UserDefinedVirtualAttributeProvider",
+ "ds-cfg-attribute-type: description", "ds-cfg-conflict-behavior: virtual-overrides-real",
+ "ds-cfg-rotation-policy: cn=" + TEST_CONNECTION_HANDLER_NAME + ", cn=connection handlers, cn=config" };
+
+ /** Test child 7 LDIF. */
+ private static final String[] TEST_CHILD_7 = new String[] {
+ "dn: cn=test child 7,cn=test children,cn=test parent 1,cn=test parents,cn=config", "objectclass: top",
+ "objectclass: ds-cfg-test-child-dummy", "cn: test child 7", "ds-cfg-enabled: false",
+ "ds-cfg-java-class: org.opends.server.extensions.UserDefinedVirtualAttributeProvider",
+ "ds-cfg-attribute-type: description", "ds-cfg-conflict-behavior: virtual-overrides-real",
+ "ds-cfg-rotation-policy: cn=" + TEST_CONNECTION_HANDLER_NAME + ", cn=connection handlers, cn=config" };
+
+ /** Test LDIF. */
+ private static final String[] TEST_LDIF = new String[] {
+ // Base entries.
+ "dn: cn=test parents,cn=config",
+ "objectclass: top",
+ "objectclass: ds-cfg-branch",
+ "cn: test parents",
+ "",
+ // Parent 1.
+ "dn: cn=test parent 1,cn=test parents,cn=config", "objectclass: top",
+ "objectclass: ds-cfg-test-parent-dummy", "cn: test parent 1", "ds-cfg-enabled: true",
+ "ds-cfg-java-class: org.opends.server.extensions.UserDefinedVirtualAttributeProvider",
+ "ds-cfg-attribute-type: description", "ds-cfg-conflict-behavior: virtual-overrides-real", "",
+ // Child base entries.
+ "dn:cn=test children,cn=test parent 1,cn=test parents,cn=config", "objectclass: top",
+ "objectclass: ds-cfg-branch", "cn: test children", "" };
+
+ /**
+ * The saved test child configuration "aggregation-property" property
+ * definition.
+ */
+ private AggregationPropertyDefinition<ConnectionHandlerCfgClient, ConnectionHandlerCfg>
+ aggregationPropertyDefinitionDefault = null;
+
+ /**
+ * An aggregation where the target must be enabled if the source is enabled.
+ */
+ private AggregationPropertyDefinition<ConnectionHandlerCfgClient, ConnectionHandlerCfg>
+ aggregationPropertyDefinitionTargetAndSourceMustBeEnabled = null;
+
+ /** An aggregation where the target must be enabled. */
+ private AggregationPropertyDefinition<ConnectionHandlerCfgClient, ConnectionHandlerCfg>
+ aggregationPropertyDefinitionTargetMustBeEnabled = null;
+
+ /**
+ * Sets up tests
+ *
+ * @throws Exception
+ * If the server could not be initialized.
+ */
+ @BeforeClass
+ public void setUp() throws Exception {
+ TestCfg.setUp();
+
+ // Add test managed objects.
+ TestCaseUtils.addEntries(TEST_LDIF);
+
+ // Save the aggregation property definition so that it can be
+ // replaced and restored later.
+ aggregationPropertyDefinitionDefault = TestChildCfgDefn.getInstance()
+ .getAggregationPropertyPropertyDefinition();
+
+ // Create the two test aggregation properties.
+ AggregationPropertyDefinition.Builder<ConnectionHandlerCfgClient, ConnectionHandlerCfg> builder;
+ TestChildCfgDefn d = TestChildCfgDefn.getInstance();
+ builder = AggregationPropertyDefinition.createBuilder(d, "aggregation-property");
+ builder.setOption(PropertyOption.MULTI_VALUED);
+ builder.setAdministratorAction(new AdministratorAction(AdministratorAction.Type.NONE, d,
+ "aggregation-property"));
+ builder.setDefaultBehaviorProvider(new UndefinedDefaultBehaviorProvider<String>());
+ builder.setParentPath("/");
+ builder.setRelationDefinition("connection-handler");
+ builder.setTargetIsEnabledCondition(Conditions.contains("enabled", "true"));
+ aggregationPropertyDefinitionTargetMustBeEnabled = builder.getInstance();
+ TestCfg.initializePropertyDefinition(aggregationPropertyDefinitionTargetMustBeEnabled);
+
+ builder = AggregationPropertyDefinition.createBuilder(d, "aggregation-property");
+ builder.setOption(PropertyOption.MULTI_VALUED);
+ builder.setAdministratorAction(new AdministratorAction(AdministratorAction.Type.NONE, d,
+ "aggregation-property"));
+ builder.setDefaultBehaviorProvider(new UndefinedDefaultBehaviorProvider<String>());
+ builder.setParentPath("/");
+ builder.setRelationDefinition("connection-handler");
+ builder.setTargetIsEnabledCondition(Conditions.contains("enabled", "true"));
+ builder.setTargetNeedsEnablingCondition(Conditions.contains("mandatory-boolean-property", "true"));
+ aggregationPropertyDefinitionTargetAndSourceMustBeEnabled = builder.getInstance();
+ TestCfg.initializePropertyDefinition(aggregationPropertyDefinitionTargetAndSourceMustBeEnabled);
+ }
+
+ /**
+ * Tears down test environment.
+ *
+ * @throws Exception
+ * If the test entries could not be removed.
+ */
+ @AfterClass
+ public void tearDown() throws Exception {
+ TestCfg.cleanup();
+
+ // Restore the test child aggregation definition.
+ TestCfg.addPropertyDefinition(aggregationPropertyDefinitionDefault);
+
+ // Remove test entries.
+ deleteSubtree("cn=test parents,cn=config");
+ }
+
+ /**
+ * Tests that aggregation is rejected when the LDAP DN contains a valid RDN
+ * but an invalid parent DN.
+ *
+ * @throws Exception
+ * If the test unexpectedly fails.
+ */
+ @Test
+ public void testAggregationBadBaseDN() throws Exception {
+ // Add the entry.
+ TestCaseUtils.addEntry(TEST_CHILD_3);
+
+ try {
+ TestParentCfg parent = getParent("test parent 1");
+ parent.getTestChild("test child 3");
+ Assert.fail("Unexpectedly added test child 3 when it had a bad aggregation value");
+ } catch (ConfigException e) {
+ // Check that we have a decoding exception as the cause and
+ // there was only one cause the illegal property value.
+ Throwable cause = e.getCause();
+ if (cause instanceof ServerManagedObjectDecodingException) {
+ ServerManagedObjectDecodingException de = (ServerManagedObjectDecodingException) cause;
+
+ Collection<PropertyException> causes = de.getCauses();
+ Assert.assertEquals(causes.size(), 1);
+
+ cause = causes.iterator().next();
+ if (cause instanceof IllegalPropertyValueStringException) {
+ IllegalPropertyValueStringException pe = (IllegalPropertyValueStringException) cause;
+ Assert.assertEquals(pe.getPropertyDefinition(), TestChildCfgDefn.getInstance()
+ .getAggregationPropertyPropertyDefinition());
+ Assert.assertEquals(pe.getIllegalValueString(),
+ "cn=LDAP Connection Handler, cn=bad rdn, cn=config");
+ } else {
+ // Got an unexpected cause.
+ throw e;
+ }
+ } else {
+ // Got an unexpected cause.
+ throw e;
+ }
+ } finally {
+ deleteSubtree("cn=test child 3,cn=test children,cn=test parent 1,cn=test parents,cn=config");
+ }
+ }
+
+ /**
+ * Tests that aggregation is rejected by a constraint violation when the DN
+ * values are dangling.
+ *
+ * @throws Exception
+ * If the test unexpectedly fails.
+ */
+ @Test
+ public void testAggregationDanglingReference() throws Exception {
+ // Add the entry.
+ TestCaseUtils.addEntry(TEST_CHILD_5);
+
+ try {
+ TestParentCfg parent = getParent("test parent 1");
+ parent.getTestChild("test child 5");
+ Assert.fail("Unexpectedly added test child 5 when it had a dangling reference");
+ } catch (ConfigException e) {
+ // Check that we have a constraint violation as the cause.
+ Throwable cause = e.getCause();
+ if (cause instanceof ConstraintViolationException) {
+ ConstraintViolationException cve = (ConstraintViolationException) cause;
+ Collection<LocalizableMessage> causes = cve.getMessages();
+ Assert.assertEquals(causes.size(), 2);
+ } else {
+ // Got an unexpected cause.
+ throw e;
+ }
+ } finally {
+ deleteSubtree("cn=test child 5,cn=test children,cn=test parent 1,cn=test parents,cn=config");
+ }
+ }
+
+ /**
+ * Tests that aggregation is rejected by a constraint violation when an
+ * enabled component references a disabled component and the referenced
+ * component must always be enabled.
+ *
+ * @throws Exception
+ * If the test unexpectedly fails.
+ */
+ @Test
+ public void testAggregationDisabledReference1() throws Exception {
+ // Add the entry and the connection handler.
+ TestCaseUtils.addEntry(TEST_CHILD_6);
+ try {
+ createConnectionHandler(false);
+ } catch (Exception e) {
+ deleteSubtree(TEST_CHILD_6_DN);
+ throw e;
+ }
+
+ // Register the temporary aggregation definition.
+ TestCfg.removeConstraint(aggregationPropertyDefinitionDefault.getSourceConstraint());
+ TestCfg.addPropertyDefinition(aggregationPropertyDefinitionTargetMustBeEnabled);
+ TestCfg.addConstraint(aggregationPropertyDefinitionTargetMustBeEnabled.getSourceConstraint());
+
+ try {
+ TestParentCfg parent = getParent("test parent 1");
+ parent.getTestChild("test child 6");
+ Assert.fail("Unexpectedly added test child 6 when it had a disabled reference");
+ } catch (ConfigException e) {
+ // Check that we have a constraint violation as the cause.
+ Throwable cause = e.getCause();
+ if (cause instanceof ConstraintViolationException) {
+ ConstraintViolationException cve = (ConstraintViolationException) cause;
+ Collection<LocalizableMessage> causes = cve.getMessages();
+ Assert.assertEquals(causes.size(), 1);
+ } else {
+ // Got an unexpected cause.
+ throw e;
+ }
+ } finally {
+ // Put back the default aggregation definition.
+ TestCfg.removeConstraint(aggregationPropertyDefinitionTargetMustBeEnabled.getSourceConstraint());
+ TestCfg.addPropertyDefinition(aggregationPropertyDefinitionDefault);
+ TestCfg.addConstraint(aggregationPropertyDefinitionDefault.getSourceConstraint());
+
+ try {
+ deleteSubtree(TEST_CHILD_6_DN);
+ } finally {
+ deleteConnectionHandler();
+ }
+ }
+ }
+
+ /**
+ * Tests that aggregation is rejected by a constraint violation when a
+ * disabled component references a disabled component and the referenced
+ * component must always be enabled.
+ *
+ * @throws Exception
+ * If the test unexpectedly fails.
+ */
+ @Test
+ public void testAggregationDisabledReference2() throws Exception {
+ // Add the entry.
+ TestCaseUtils.addEntry(TEST_CHILD_7);
+ try {
+ createConnectionHandler(false);
+ } catch (Exception e) {
+ deleteSubtree(TEST_CHILD_7_DN);
+ throw e;
+ }
+
+ // Register the temporary aggregation definition.
+ TestCfg.removeConstraint(aggregationPropertyDefinitionDefault.getSourceConstraint());
+ TestCfg.addPropertyDefinition(aggregationPropertyDefinitionTargetMustBeEnabled);
+ TestCfg.addConstraint(aggregationPropertyDefinitionTargetMustBeEnabled.getSourceConstraint());
+
+ try {
+ TestParentCfg parent = getParent("test parent 1");
+ parent.getTestChild("test child 7");
+ Assert.fail("Unexpectedly added test child 7 when it had a disabled reference");
+ } catch (ConfigException e) {
+ // Check that we have a constraint violation as the cause.
+ Throwable cause = e.getCause();
+ if (cause instanceof ConstraintViolationException) {
+ ConstraintViolationException cve = (ConstraintViolationException) cause;
+ Collection<LocalizableMessage> causes = cve.getMessages();
+ Assert.assertEquals(causes.size(), 1);
+ } else {
+ // Got an unexpected cause.
+ throw e;
+ }
+ } finally {
+ // Put back the default aggregation definition.
+ TestCfg.removeConstraint(aggregationPropertyDefinitionTargetMustBeEnabled.getSourceConstraint());
+ TestCfg.addPropertyDefinition(aggregationPropertyDefinitionDefault);
+ TestCfg.addConstraint(aggregationPropertyDefinitionDefault.getSourceConstraint());
+
+ try {
+ deleteSubtree(TEST_CHILD_7_DN);
+ } finally {
+ deleteConnectionHandler();
+ }
+ }
+ }
+
+ /**
+ * Tests that aggregation is rejected by a constraint violation when an
+ * enabled component references a disabled component and the referenced
+ * component must always be enabled when the referencing component is
+ * enabled.
+ *
+ * @throws Exception
+ * If the test unexpectedly fails.
+ */
+ @Test
+ public void testAggregationDisabledReference3() throws Exception {
+ // Add the entry.
+ TestCaseUtils.addEntry(TEST_CHILD_6);
+ try {
+ createConnectionHandler(false);
+ } catch (Exception e) {
+ deleteSubtree(TEST_CHILD_6_DN);
+ throw e;
+ }
+
+ // Register the temporary aggregation definition.
+ TestCfg.removeConstraint(aggregationPropertyDefinitionDefault.getSourceConstraint());
+ TestCfg.addPropertyDefinition(aggregationPropertyDefinitionTargetAndSourceMustBeEnabled);
+ TestCfg.addConstraint(aggregationPropertyDefinitionTargetAndSourceMustBeEnabled.getSourceConstraint());
+
+ try {
+ TestParentCfg parent = getParent("test parent 1");
+ parent.getTestChild("test child 6");
+ Assert.fail("Unexpectedly added test child 6 when it had a disabled reference");
+ } catch (ConfigException e) {
+ // Check that we have a constraint violation as the cause.
+ Throwable cause = e.getCause();
+ if (cause instanceof ConstraintViolationException) {
+ ConstraintViolationException cve = (ConstraintViolationException) cause;
+ Collection<LocalizableMessage> causes = cve.getMessages();
+ Assert.assertEquals(causes.size(), 1);
+ } else {
+ // Got an unexpected cause.
+ throw e;
+ }
+ } finally {
+ // Put back the default aggregation definition.
+ TestCfg.removeConstraint(aggregationPropertyDefinitionTargetAndSourceMustBeEnabled.getSourceConstraint());
+ TestCfg.addPropertyDefinition(aggregationPropertyDefinitionDefault);
+ TestCfg.addConstraint(aggregationPropertyDefinitionDefault.getSourceConstraint());
+
+ try {
+ deleteSubtree(TEST_CHILD_6_DN);
+ } finally {
+ deleteConnectionHandler();
+ }
+ }
+ }
+
+ /**
+ * Tests that aggregation is allowed when a disabled component references a
+ * disabled component and the referenced component must always be enabled
+ * when the referencing component is enabled.
+ *
+ * @throws Exception
+ * If the test unexpectedly fails.
+ */
+ @Test
+ public void testAggregationDisabledReference4() throws Exception {
+ // Add the entry.
+ TestCaseUtils.addEntry(TEST_CHILD_7);
+ try {
+ createConnectionHandler(false);
+ } catch (Exception e) {
+ deleteSubtree(TEST_CHILD_7_DN);
+ throw e;
+ }
+
+ // Register the temporary aggregation definition.
+ TestCfg.removeConstraint(aggregationPropertyDefinitionDefault.getSourceConstraint());
+ TestCfg.addPropertyDefinition(aggregationPropertyDefinitionTargetAndSourceMustBeEnabled);
+ TestCfg.addConstraint(aggregationPropertyDefinitionTargetAndSourceMustBeEnabled.getSourceConstraint());
+
+ try {
+ TestParentCfg parent = getParent("test parent 1");
+ parent.getTestChild("test child 7");
+ } finally {
+ // Put back the default aggregation definition.
+ TestCfg.removeConstraint(aggregationPropertyDefinitionTargetAndSourceMustBeEnabled.getSourceConstraint());
+ TestCfg.addPropertyDefinition(aggregationPropertyDefinitionDefault);
+ TestCfg.addConstraint(aggregationPropertyDefinitionDefault.getSourceConstraint());
+
+ try {
+ deleteSubtree(TEST_CHILD_7_DN);
+ } finally {
+ deleteConnectionHandler();
+ }
+ }
+ }
+
+ /**
+ * Tests that aggregation contains no values when it contains does not
+ * contain any DN attribute values.
+ *
+ * @throws Exception
+ * If the test unexpectedly fails.
+ */
+ @Test
+ public void testAggregationEmpty() throws Exception {
+ // Add the entry.
+ TestCaseUtils.addEntry(TEST_CHILD_1);
+
+ try {
+ TestParentCfg parent = getParent("test parent 1");
+ assertChild1(parent.getTestChild("test child 1"));
+ } finally {
+ deleteSubtree("cn=test child 1,cn=test children,cn=test parent 1,cn=test parents,cn=config");
+ }
+ }
+
+ /**
+ * Tests that aggregation contains multiple valid values when it contains a
+ * multiple valid DN attribute values.
+ *
+ * @throws Exception
+ * If the test unexpectedly fails.
+ */
+ @Test
+ public void testAggregationMultipleValues() throws Exception {
+ // Add the entry.
+ TestCaseUtils.addEntry(TEST_CHILD_4);
+
+ try {
+ TestParentCfg parent = getParent("test parent 1");
+ assertChild4(parent.getTestChild("test child 4"));
+ } finally {
+ deleteSubtree("cn=test child 4,cn=test children,cn=test parent 1,cn=test parents,cn=config");
+ }
+ }
+
+ /**
+ * Tests that aggregation contains single valid value when it contains a
+ * single valid DN attribute values.
+ *
+ * @throws Exception
+ * If the test unexpectedly fails.
+ */
+ @Test
+ public void testAggregationSingle() throws Exception {
+ // Add the entry.
+ TestCaseUtils.addEntry(TEST_CHILD_2);
+
+ try {
+ TestParentCfg parent = getParent("test parent 1");
+ assertChild2(parent.getTestChild("test child 2"));
+ } finally {
+ deleteSubtree("cn=test child 2,cn=test children,cn=test parent 1,cn=test parents,cn=config");
+ }
+ }
+
+ /**
+ * Tests that it is impossible to delete a referenced component when the
+ * referenced component must always exist regardless of whether the
+ * referencing component is enabled or not.
+ *
+ * @throws Exception
+ * If the test unexpectedly fails.
+ */
+ @Test
+ public void testCannotDeleteReferencedComponent() throws Exception {
+ // Add the entry.
+ TestCaseUtils.addEntry(TEST_CHILD_7);
+ try {
+ createConnectionHandler(true);
+ } catch (Exception e) {
+ deleteSubtree(TEST_CHILD_7_DN);
+ throw e;
+ }
+
+ // Register the temporary aggregation definition.
+ TestCfg.removeConstraint(aggregationPropertyDefinitionDefault.getSourceConstraint());
+ TestCfg.addPropertyDefinition(aggregationPropertyDefinitionTargetMustBeEnabled);
+ TestCfg.addConstraint(aggregationPropertyDefinitionTargetMustBeEnabled.getSourceConstraint());
+
+ ConfigurationDeleteListener<TestChildCfg> dl = new DummyDeleteListener();
+ ConfigurationChangeListener<TestChildCfg> cl = new DummyChangeListener();
+ try {
+ // Retrieve the parent and child managed objects and register
+ // delete and change listeners respectively in order to trigger
+ // the constraint call-backs.
+ TestParentCfg parent = getParent("test parent 1");
+ parent.addTestChildDeleteListener(dl);
+
+ TestChildCfg child = parent.getTestChild("test child 7");
+ child.addChangeListener(cl);
+
+ // Now attempt to delete the referenced connection handler.
+ // This should fail.
+ try {
+ deleteConnectionHandler();
+ Assert.fail("Successfully deleted a referenced component");
+ } catch (OperationRejectedException e) {
+ // This is the expected exception - do nothing.
+ }
+ } finally {
+ try {
+ deleteSubtree(TEST_CHILD_7_DN);
+ } finally {
+ try {
+ deleteConnectionHandler();
+ } catch (ManagedObjectNotFoundException e) {
+ // Ignore as it may have been deleted already.
+ } finally {
+ // Remove the temporary delete listener.
+ TestParentCfg parent = getParent("test parent 1");
+ parent.removeTestChildDeleteListener(dl);
+
+ // Put back the default aggregation definition.
+ TestCfg.removeConstraint(aggregationPropertyDefinitionTargetMustBeEnabled.getSourceConstraint());
+ TestCfg.addPropertyDefinition(aggregationPropertyDefinitionDefault);
+ TestCfg.addConstraint(aggregationPropertyDefinitionDefault.getSourceConstraint());
+ }
+ }
+ }
+ }
+
+ /**
+ * Tests that it is impossible to disable a referenced component when the
+ * referenced component must always be enabled regardless of whether the
+ * referencing component is enabled or not.
+ *
+ * @throws Exception
+ * If the test unexpectedly fails.
+ */
+ @Test
+ public void testCannotDisableReferencedComponent() throws Exception {
+ // Add the entry.
+ TestCaseUtils.addEntry(TEST_CHILD_7);
+ try {
+ createConnectionHandler(true);
+ } catch (Exception e) {
+ deleteSubtree(TEST_CHILD_7_DN);
+ throw e;
+ }
+
+ // Register the temporary aggregation definition.
+ TestCfg.removeConstraint(aggregationPropertyDefinitionDefault.getSourceConstraint());
+ TestCfg.addPropertyDefinition(aggregationPropertyDefinitionTargetMustBeEnabled);
+ TestCfg.addConstraint(aggregationPropertyDefinitionTargetMustBeEnabled.getSourceConstraint());
+
+ ConfigurationDeleteListener<TestChildCfg> dl = new DummyDeleteListener();
+ ConfigurationChangeListener<TestChildCfg> cl = new DummyChangeListener();
+ try {
+ // Retrieve the parent and child managed objects and register
+ // delete and change listeners respectively in order to trigger
+ // the constraint call-backs.
+ TestParentCfg parent = getParent("test parent 1");
+ parent.addTestChildDeleteListener(dl);
+
+ TestChildCfg child = parent.getTestChild("test child 7");
+ child.addChangeListener(cl);
+
+ // Now attempt to disable the referenced connection handler.
+ // This should fail.
+ try {
+ RootCfgClient root = TestCaseUtils.getRootConfiguration();
+ ConnectionHandlerCfgClient client = root.getConnectionHandler(TEST_CONNECTION_HANDLER_NAME);
+ client.setEnabled(false);
+ client.commit();
+ Assert.fail("Successfully disabled a referenced component");
+ } catch (OperationRejectedException e) {
+ // This is the expected exception - do nothing.
+ }
+ } finally {
+ try {
+ deleteSubtree(TEST_CHILD_7_DN);
+ } finally {
+ try {
+ deleteConnectionHandler();
+ } finally {
+ // Remove the temporary delete listener.
+ TestParentCfg parent = getParent("test parent 1");
+ parent.removeTestChildDeleteListener(dl);
+
+ // Put back the default aggregation definition.
+ TestCfg.removeConstraint(aggregationPropertyDefinitionTargetMustBeEnabled.getSourceConstraint());
+ TestCfg.addPropertyDefinition(aggregationPropertyDefinitionDefault);
+ TestCfg.addConstraint(aggregationPropertyDefinitionDefault.getSourceConstraint());
+ }
+ }
+ }
+ }
+
+ /** Assert that the values of child 1 are correct. */
+ private void assertChild1(TestChildCfg child) {
+ Assert.assertEquals(child.getMandatoryClassProperty(),
+ "org.opends.server.extensions.UserDefinedVirtualAttributeProvider");
+ Assert.assertEquals(child.getMandatoryReadOnlyAttributeTypeProperty(),
+ DirectoryServer.getAttributeType("description"));
+ assertSetEquals(child.getAggregationProperty(), new String[0]);
+ }
+
+ /** Assert that the values of child 2 are correct. */
+ private void assertChild2(TestChildCfg child) {
+ Assert.assertEquals(child.getMandatoryClassProperty(),
+ "org.opends.server.extensions.UserDefinedVirtualAttributeProvider");
+ Assert.assertEquals(child.getMandatoryReadOnlyAttributeTypeProperty(),
+ DirectoryServer.getAttributeType("description"));
+
+ // Test normalization.
+ assertSetEquals(child.getAggregationProperty(), "LDAP Connection Handler");
+ assertSetEquals(child.getAggregationProperty(), " LDAP Connection Handler ");
+ assertSetEquals(child.getAggregationProperty(), " ldap connection HANDLER ");
+ }
+
+ /** Assert that the values of child 4 are correct. */
+ private void assertChild4(TestChildCfg child) {
+ Assert.assertEquals(child.getMandatoryClassProperty(),
+ "org.opends.server.extensions.UserDefinedVirtualAttributeProvider");
+ Assert.assertEquals(child.getMandatoryReadOnlyAttributeTypeProperty(),
+ DirectoryServer.getAttributeType("description"));
+ assertSetEquals(child.getAggregationProperty(), "LDAPS Connection Handler", "LDAP Connection Handler");
+ }
+
+ /** Asserts that the actual set of DNs contains the expected values. */
+ private void assertSetEquals(SortedSet<String> actual, String... expected) {
+ SortedSet<String> values = new TreeSet<String>(TestChildCfgDefn.getInstance()
+ .getAggregationPropertyPropertyDefinition());
+ if (expected != null) {
+ for (String value : expected) {
+ values.add(value);
+ }
+ }
+ Assert.assertEquals((Object) actual, (Object) values);
+ }
+
+ /** Creates a test connection handler for testing. */
+ private void createConnectionHandler(boolean enabled) throws Exception {
+ RootCfgClient root = TestCaseUtils.getRootConfiguration();
+ LDAPConnectionHandlerCfgClient client = root.createConnectionHandler(
+ LDAPConnectionHandlerCfgDefn.getInstance(), TEST_CONNECTION_HANDLER_NAME, null);
+ client.setEnabled(enabled);
+ client.setListenPort(1000);
+ client.commit();
+ }
+
+ /** Deletes the test connection handler after testing. */
+ private void deleteConnectionHandler() throws Exception {
+ RootCfgClient root = TestCaseUtils.getRootConfiguration();
+ root.removeConnectionHandler(TEST_CONNECTION_HANDLER_NAME);
+ }
+
+ /** Gets the named parent configuration. */
+ private TestParentCfg getParent(String name) throws IllegalArgumentException, ConfigException {
+ ServerManagedObject<RootCfg> root = serverContext.getRootConfigurationManagedObject();
+ return root.getChild(TestCfg.getTestOneToManyParentRelationDefinition(), name).getConfiguration();
+ }
+}
diff --git a/opendj-sdk/opendj-admin/src/test/java/org/opends/server/admin/server/ConstraintTest.java b/opendj-sdk/opendj-admin/src/test/java/org/opends/server/admin/server/ConstraintTest.java
new file mode 100644
index 0000000..813a3a3
--- /dev/null
+++ b/opendj-sdk/opendj-admin/src/test/java/org/opends/server/admin/server/ConstraintTest.java
@@ -0,0 +1,489 @@
+/*
+ * 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 legal-notices/CDDLv1_0.txt
+ * or http://forgerock.org/license/CDDLv1.0.html.
+ * 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 legal-notices/CDDLv1_0.txt.
+ * 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
+ *
+ *
+ * Copyright 2008 Sun Microsystems, Inc.
+ */
+package org.opends.server.admin.server;
+
+import java.util.List;
+
+import javax.naming.OperationNotSupportedException;
+import javax.naming.ldap.LdapName;
+
+import org.opends.server.admin.AdminTestCase;
+import org.opends.server.admin.TestCfg;
+import org.opends.server.admin.TestChildCfg;
+import org.opends.server.admin.TestChildCfgDefn;
+import org.opends.server.admin.TestParentCfg;
+import org.opends.server.config.ConfigException;
+import org.opends.server.types.ConfigChangeResult;
+import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+/**
+ * Test cases for constraints on the server-side.
+ */
+public final class ConstraintTest extends AdminTestCase {
+
+ // Child DN.
+ private static final String TEST_CHILD_1_DN = "cn=test child 1,cn=test children,cn=test parent 1,cn=test parents,cn=config";
+
+ /**
+ * A test child add listener.
+ */
+ private static class AddListener implements ConfigurationAddListener<TestChildCfg> {
+
+ /**
+ * {@inheritDoc}
+ */
+ public ConfigChangeResult applyConfigurationAdd(TestChildCfg configuration) {
+ return new ConfigChangeResult(ResultCode.SUCCESS, false);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isConfigurationAddAcceptable(TestChildCfg configuration, List<Message> unacceptableReasons) {
+ return true;
+ }
+
+ }
+
+ /**
+ * A test child delete listener.
+ */
+ private static class DeleteListener implements ConfigurationDeleteListener<TestChildCfg> {
+
+ /**
+ * {@inheritDoc}
+ */
+ public ConfigChangeResult applyConfigurationDelete(TestChildCfg configuration) {
+ return new ConfigChangeResult(ResultCode.SUCCESS, false);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isConfigurationDeleteAcceptable(TestChildCfg configuration, List<Message> unacceptableReasons) {
+ return true;
+ }
+
+ }
+
+ /**
+ * A test child change listener.
+ */
+ private static class ChangeListener implements ConfigurationChangeListener<TestChildCfg> {
+
+ /**
+ * {@inheritDoc}
+ */
+ public ConfigChangeResult applyConfigurationChange(TestChildCfg configuration) {
+ return new ConfigChangeResult(ResultCode.SUCCESS, false);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isConfigurationChangeAcceptable(TestChildCfg configuration, List<Message> unacceptableReasons) {
+ return true;
+ }
+
+ }
+
+ // Test child 1 LDIF.
+ private static final String[] TEST_CHILD_1 = new String[] {
+ "dn: cn=test child 1,cn=test children,cn=test parent 1,cn=test parents,cn=config", "objectclass: top",
+ "objectclass: ds-cfg-test-child-dummy", "cn: test child 1", "ds-cfg-enabled: true",
+ "ds-cfg-java-class: org.opends.server.extensions.UserDefinedVirtualAttributeProvider",
+ "ds-cfg-attribute-type: description", "ds-cfg-conflict-behavior: virtual-overrides-real" };
+
+ // Test LDIF.
+ private static final String[] TEST_LDIF = new String[] {
+ // Base entries.
+ "dn: cn=test parents,cn=config",
+ "objectclass: top",
+ "objectclass: ds-cfg-branch",
+ "cn: test parents",
+ "",
+ // Parent 1 - uses default values for
+ // optional-multi-valued-dn-property.
+ "dn: cn=test parent 1,cn=test parents,cn=config", "objectclass: top",
+ "objectclass: ds-cfg-test-parent-dummy", "cn: test parent 1", "ds-cfg-enabled: true",
+ "ds-cfg-java-class: org.opends.server.extensions.UserDefinedVirtualAttributeProvider",
+ "ds-cfg-attribute-type: description", "ds-cfg-conflict-behavior: virtual-overrides-real", "",
+ // Child base entries.
+ "dn:cn=test children,cn=test parent 1,cn=test parents,cn=config", "objectclass: top",
+ "objectclass: ds-cfg-branch", "cn: test children", "", };
+
+ // JNDI LDAP context.
+ private JNDIDirContextAdaptor adaptor = null;
+
+ /**
+ * Sets up tests
+ *
+ * @throws Exception
+ * If the server could not be initialized.
+ */
+ @BeforeClass
+ public void setUp() throws Exception {
+ // This test suite depends on having the schema available, so
+ // we'll start the server.
+ TestCaseUtils.startServer();
+ TestCfg.setUp();
+
+ // Add test managed objects.
+ TestCaseUtils.addEntries(TEST_LDIF);
+ }
+
+ /**
+ * Tears down test environment.
+ *
+ * @throws Exception
+ * If the test entries could not be removed.
+ */
+ @AfterClass
+ public void tearDown() throws Exception {
+ TestCfg.cleanup();
+
+ // Remove test entries.
+ deleteSubtree("cn=test parents,cn=config");
+ }
+
+ /**
+ * Tests that retrieval can succeed.
+ *
+ * @throws Exception
+ * If the test unexpectedly fails.
+ */
+ @Test
+ public void testGetManagedObjectSuccess() throws Exception {
+ MockConstraint constraint = new MockConstraint(true, false);
+
+ try {
+ TestCaseUtils.addEntry(TEST_CHILD_1);
+ TestCfg.addConstraint(constraint);
+
+ TestParentCfg parent = getParent("test parent 1");
+ parent.getTestChild("test child 1");
+ } finally {
+ TestCfg.removeConstraint(constraint);
+
+ try {
+ deleteSubtree(TEST_CHILD_1_DN);
+ } catch (Exception e) {
+ // Do nothing.
+ }
+ }
+ }
+
+ /**
+ * Tests that retrieval can fail.
+ *
+ * @throws Exception
+ * If the test unexpectedly fails.
+ */
+ @Test
+ public void testGetManagedObjectFail() throws Exception {
+ MockConstraint constraint = new MockConstraint(false, true);
+
+ try {
+ TestCaseUtils.addEntry(TEST_CHILD_1);
+ TestCfg.addConstraint(constraint);
+
+ TestParentCfg parent = getParent("test parent 1");
+ parent.getTestChild("test child 1");
+ } catch (ConfigException e) {
+ Throwable cause = e.getCause();
+ if (cause instanceof ConstraintViolationException) {
+ ConstraintViolationException cve = (ConstraintViolationException) cause;
+ Assert.assertEquals(cve.getMessages().size(), 1);
+ Assert.assertSame(cve.getManagedObject().getManagedObjectDefinition(), TestChildCfgDefn.getInstance());
+ } else {
+ // Wrong cause.
+ throw e;
+ }
+ } finally {
+ TestCfg.removeConstraint(constraint);
+
+ try {
+ deleteSubtree(TEST_CHILD_1_DN);
+ } catch (Exception e) {
+ // Do nothing.
+ }
+ }
+ }
+
+ /**
+ * Tests that an add constraint can succeed.
+ *
+ * @throws Exception
+ * If the test unexpectedly fails.
+ */
+ @Test
+ public void testAddConstraintSuccess() throws Exception {
+ TestParentCfg parent = getParent("test parent 1");
+ AddListener listener = new AddListener();
+ parent.addTestChildAddListener(listener);
+
+ MockConstraint constraint = new MockConstraint(true, false);
+ TestCfg.addConstraint(constraint);
+
+ try {
+ try {
+ // Add the entry.
+ addEntry(ResultCode.SUCCESS, TEST_CHILD_1);
+ } finally {
+ try {
+ deleteSubtree(TEST_CHILD_1_DN);
+ } catch (Exception e) {
+ // Do nothing.
+ }
+ }
+ } finally {
+ TestCfg.removeConstraint(constraint);
+ parent.removeTestChildAddListener(listener);
+ }
+ }
+
+ /**
+ * Tests that an add constraint can fail.
+ *
+ * @throws Exception
+ * If the test unexpectedly fails.
+ */
+ @Test
+ public void testAddConstraintFail() throws Exception {
+ TestParentCfg parent = getParent("test parent 1");
+ AddListener listener = new AddListener();
+ parent.addTestChildAddListener(listener);
+
+ MockConstraint constraint = new MockConstraint(false, true);
+ TestCfg.addConstraint(constraint);
+
+ try {
+ try {
+ // Add the entry.
+ addEntry(ResultCode.UNWILLING_TO_PERFORM, TEST_CHILD_1);
+ } finally {
+ try {
+ deleteSubtree(TEST_CHILD_1_DN);
+ } catch (Exception e) {
+ // Do nothing.
+ }
+ }
+ } finally {
+ TestCfg.removeConstraint(constraint);
+ parent.removeTestChildAddListener(listener);
+ }
+ }
+
+ /**
+ * Tests that a delete constraint can succeed.
+ *
+ * @throws Exception
+ * If the test unexpectedly fails.
+ */
+ @Test
+ public void testDeleteConstraintSuccess() throws Exception {
+ TestParentCfg parent = getParent("test parent 1");
+ DeleteListener listener = new DeleteListener();
+ parent.addTestChildDeleteListener(listener);
+
+ MockConstraint constraint = new MockConstraint(false, true);
+ TestCfg.addConstraint(constraint);
+
+ try {
+ // Add the entry.
+ TestCaseUtils.addEntry(TEST_CHILD_1);
+
+ // Now delete it - this should trigger the constraint.
+ deleteSubtree(TEST_CHILD_1_DN);
+ } finally {
+ TestCfg.removeConstraint(constraint);
+ parent.removeTestChildDeleteListener(listener);
+
+ try {
+ // Clean up.
+ deleteSubtree(TEST_CHILD_1_DN);
+ } catch (Exception e) {
+ // Ignore.
+ }
+ }
+ }
+
+ /**
+ * Tests that a delete constraint can fail.
+ *
+ * @throws Exception
+ * If the test unexpectedly fails.
+ */
+ @Test
+ public void testDeleteConstraintFail() throws Exception {
+ TestParentCfg parent = getParent("test parent 1");
+ DeleteListener listener = new DeleteListener();
+ parent.addTestChildDeleteListener(listener);
+
+ MockConstraint constraint = new MockConstraint(true, false);
+ TestCfg.addConstraint(constraint);
+
+ try {
+ // Add the entry.
+ TestCaseUtils.addEntry(TEST_CHILD_1);
+ try {
+ // Now delete it - this should trigger the constraint.
+ deleteSubtree(TEST_CHILD_1_DN);
+
+ // Should not have succeeded.
+ Assert.fail("Delete constraint failed to prevent deletion");
+ } catch (OperationNotSupportedException e) {
+ // Ignore - this is the expected exception.
+ }
+ } finally {
+ TestCfg.removeConstraint(constraint);
+ parent.removeTestChildDeleteListener(listener);
+
+ try {
+ // Clean up.
+ deleteSubtree(TEST_CHILD_1_DN);
+ } catch (Exception e) {
+ // Ignore.
+ }
+ }
+ }
+
+ /**
+ * Tests that a modify constraint can succeed.
+ *
+ * @throws Exception
+ * If the test unexpectedly fails.
+ */
+ @Test
+ public void testChangeConstraintSuccess() throws Exception {
+ TestParentCfg parent = getParent("test parent 1");
+
+ MockConstraint constraint = new MockConstraint(true, false);
+
+ try {
+ // Add the entry.
+ TestCaseUtils.addEntry(TEST_CHILD_1);
+ TestChildCfg child = parent.getTestChild("test child 1");
+
+ TestCfg.addConstraint(constraint);
+ ChangeListener listener = new ChangeListener();
+ child.addChangeListener(listener);
+
+ // Now modify it.
+ String[] changes = new String[] {
+ "dn: cn=test child 1,cn=test children,cn=test parent 1,cn=test parents,cn=config",
+ "changetype: modify", "replace: ds-cfg-base-dn", "ds-cfg-base-dn: dc=new value 1,dc=com",
+ "ds-cfg-base-dn: dc=new value 2,dc=com", "-", "replace: ds-cfg-group-dn",
+ "ds-cfg-group-dn: dc=new value 3,dc=com", "ds-cfg-group-dn: dc=new value 4,dc=com" };
+
+ int result = TestCaseUtils.applyModifications(true, changes);
+ Assert.assertEquals(result, ResultCode.SUCCESS.getIntValue());
+ } finally {
+ TestCfg.removeConstraint(constraint);
+ try {
+ deleteSubtree(TEST_CHILD_1_DN);
+ } catch (Exception e) {
+ // Ignore.
+ }
+ }
+ }
+
+ /**
+ * Tests that a modify constraint can fail.
+ *
+ * @throws Exception
+ * If the test unexpectedly fails.
+ */
+ @Test
+ public void testChangeConstraintFail() throws Exception {
+ TestParentCfg parent = getParent("test parent 1");
+ MockConstraint constraint = new MockConstraint(false, true);
+
+ try {
+ // Add the entry.
+ TestCaseUtils.addEntry(TEST_CHILD_1);
+ TestChildCfg child = parent.getTestChild("test child 1");
+
+ TestCfg.addConstraint(constraint);
+ ChangeListener listener = new ChangeListener();
+ child.addChangeListener(listener);
+
+ // Now modify it.
+ String[] changes = new String[] {
+ "dn: cn=test child 1,cn=test children,cn=test parent 1,cn=test parents,cn=config",
+ "changetype: modify", "replace: ds-cfg-base-dn", "ds-cfg-base-dn: dc=new value 1,dc=com",
+ "ds-cfg-base-dn: dc=new value 2,dc=com", "-", "replace: ds-cfg-group-dn",
+ "ds-cfg-group-dn: dc=new value 3,dc=com", "ds-cfg-group-dn: dc=new value 4,dc=com" };
+
+ int result = TestCaseUtils.applyModifications(true, changes);
+ Assert.assertEquals(result, ResultCode.UNWILLING_TO_PERFORM.getIntValue());
+ } finally {
+ TestCfg.removeConstraint(constraint);
+ try {
+ deleteSubtree(TEST_CHILD_1_DN);
+ } catch (Exception e) {
+ // Ignore.
+ }
+ }
+ }
+
+ // Add an entry and check its result.
+ private void addEntry(ResultCode expected, String... lines) throws Exception {
+ Entry entry = TestCaseUtils.makeEntry(lines);
+
+ InternalClientConnection conn = InternalClientConnection.getRootConnection();
+
+ AddOperation add = conn.processAdd(entry.getDN(), entry.getObjectClasses(), entry.getUserAttributes(),
+ entry.getOperationalAttributes());
+
+ Assert.assertEquals(add.getResultCode(), expected, add.getErrorMessage().toString());
+ }
+
+ // Deletes the named sub-tree.
+ private void deleteSubtree(String dn) throws Exception {
+ getAdaptor().deleteSubtree(new LdapName(dn));
+ }
+
+ // Gets the JNDI connection for the test server instance.
+ private synchronized JNDIDirContextAdaptor getAdaptor() throws Exception {
+ if (adaptor == null) {
+ adaptor = JNDIDirContextAdaptor.simpleSSLBind("127.0.0.1", TestCaseUtils.getServerAdminPort(),
+ "cn=directory manager", "password");
+ }
+ return adaptor;
+ }
+
+ // Gets the named parent configuration.
+ private TestParentCfg getParent(String name) throws IllegalArgumentException, ConfigException {
+ ServerManagedObject<RootCfg> root = serverContext.getRootConfigurationManagedObject();
+ TestParentCfg parent = root.getChild(TestCfg.getTestOneToManyParentRelationDefinition(), name)
+ .getConfiguration();
+ return parent;
+ }
+}
diff --git a/opendj-sdk/opendj-admin/src/test/java/org/opends/server/admin/server/DNBuilderTest.java b/opendj-sdk/opendj-admin/src/test/java/org/opends/server/admin/server/DNBuilderTest.java
new file mode 100644
index 0000000..f3e8eb3
--- /dev/null
+++ b/opendj-sdk/opendj-admin/src/test/java/org/opends/server/admin/server/DNBuilderTest.java
@@ -0,0 +1,165 @@
+/*
+ * 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 legal-notices/CDDLv1_0.txt
+ * or http://forgerock.org/license/CDDLv1.0.html.
+ * 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 legal-notices/CDDLv1_0.txt.
+ * 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
+ *
+ *
+ * Copyright 2008 Sun Microsystems, Inc.
+ */
+package org.opends.server.admin.server;
+
+import static org.testng.Assert.*;
+
+import org.forgerock.opendj.ldap.DN;
+import org.opends.server.admin.AdminTestCase;
+import org.opends.server.admin.Configuration;
+import org.opends.server.admin.ConfigurationClient;
+import org.opends.server.admin.LDAPProfile;
+import org.opends.server.admin.ManagedObjectPath;
+import org.opends.server.admin.RelationDefinition;
+import org.opends.server.admin.SingletonRelationDefinition;
+import org.opends.server.admin.TestCfg;
+import org.opends.server.admin.TestChildCfg;
+import org.opends.server.admin.TestChildCfgClient;
+import org.opends.server.admin.TestChildCfgDefn;
+import org.opends.server.admin.TestParentCfgDefn;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+/**
+ * Test cases for the server DNBuilder class.
+ */
+public final class DNBuilderTest extends AdminTestCase {
+
+ /**
+ * Sets up tests
+ *
+ * @throws Exception
+ * If the server could not be initialized.
+ */
+ @BeforeClass
+ public void setUp() throws Exception {
+ disableClassValidationForProperties();
+ TestCfg.setUp();
+ }
+
+ /**
+ * Tears down test environment.
+ */
+ @AfterClass
+ public void tearDown() {
+ TestCfg.cleanup();
+ }
+
+ /**
+ * Tests construction of a DN from a managed object path containing a
+ * subordinate one-to-many relationship.
+ *
+ * @throws Exception
+ * If an unexpected exception occurred.
+ */
+ @Test
+ public void testCreateOneToMany() throws Exception {
+ // First create the path.
+ ManagedObjectPath<? extends ConfigurationClient, ? extends Configuration> path = ManagedObjectPath
+ .emptyPath();
+
+ path = path.child(TestCfg.getTestOneToManyParentRelationDefinition(), "test-parent-1");
+ path = path.child(TestParentCfgDefn.getInstance().getTestChildrenRelationDefinition(), "test-child-1");
+
+ // Now serialize it.
+ DN actual = DNBuilder.create(path);
+ DN expected = DN.valueOf("cn=test-child-1,cn=test children,cn=test-parent-1,cn=test parents,cn=config");
+
+ assertEquals(actual, expected);
+ }
+
+ /**
+ * Tests construction of a DN from a managed object path containing a
+ * subordinate one-to-one relationship.
+ *
+ * @throws Exception
+ * If an unexpected exception occurred.
+ */
+ @Test
+ public void testCreateOneToOne() throws Exception {
+ // First create the path.
+ ManagedObjectPath<? extends ConfigurationClient, ? extends Configuration> path = ManagedObjectPath
+ .emptyPath();
+
+ SingletonRelationDefinition.Builder<TestChildCfgClient, TestChildCfg> b = new SingletonRelationDefinition.Builder<TestChildCfgClient, TestChildCfg>(
+ TestParentCfgDefn.getInstance(), "singleton-test-child", TestChildCfgDefn.getInstance());
+ final SingletonRelationDefinition<TestChildCfgClient, TestChildCfg> r2 = b.getInstance();
+ LDAPProfile.Wrapper wrapper = new LDAPProfile.Wrapper() {
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getRelationRDNSequence(RelationDefinition<?, ?> r) {
+ if (r == r2) {
+ return "cn=singleton-test-child";
+ } else {
+ return null;
+ }
+ }
+
+ };
+
+ path = path.child(TestCfg.getTestOneToManyParentRelationDefinition(), "test-parent-1");
+ path = path.child(r2);
+
+ // Now serialize it.
+ LDAPProfile.getInstance().pushWrapper(wrapper);
+ try {
+ DN actual = DNBuilder.create(path);
+ DN expected = DN.valueOf("cn=singleton-test-child,cn=test-parent-1,cn=test parents,cn=config");
+
+ assertEquals(actual, expected);
+ } finally {
+ LDAPProfile.getInstance().popWrapper();
+ }
+ }
+
+ /**
+ * Tests construction of a DN from a managed object path containing a
+ * subordinate one-to-zero-or-one relationship.
+ *
+ * @throws Exception
+ * If an unexpected exception occurred.
+ */
+ @Test
+ public void testCreateOneToZeroOrOne() throws Exception {
+ // First create the path.
+ ManagedObjectPath<? extends ConfigurationClient, ? extends Configuration> path = ManagedObjectPath
+ .emptyPath();
+
+ path = path.child(TestCfg.getTestOneToManyParentRelationDefinition(), "test-parent-1");
+ path = path.child(TestParentCfgDefn.getInstance().getOptionalTestChildRelationDefinition());
+
+ // Now serialize it.
+ DN actual = DNBuilder.create(path);
+ DN expected = DN.valueOf("cn=optional test child,cn=test-parent-1,cn=test parents,cn=config");
+
+ assertEquals(actual, expected);
+ }
+
+}
diff --git a/opendj-sdk/opendj-admin/src/test/java/org/opends/server/admin/server/DefaultBehaviorTest.java b/opendj-sdk/opendj-admin/src/test/java/org/opends/server/admin/server/DefaultBehaviorTest.java
new file mode 100644
index 0000000..b37a014
--- /dev/null
+++ b/opendj-sdk/opendj-admin/src/test/java/org/opends/server/admin/server/DefaultBehaviorTest.java
@@ -0,0 +1,711 @@
+/*
+ * 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 legal-notices/CDDLv1_0.txt
+ * or http://forgerock.org/license/CDDLv1.0.html.
+ * 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 legal-notices/CDDLv1_0.txt.
+ * 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
+ *
+ *
+ * Copyright 2008 Sun Microsystems, Inc.
+ */
+package org.opends.server.admin.server;
+
+import java.util.List;
+import java.util.SortedSet;
+
+import javax.naming.ldap.LdapName;
+
+import org.opends.server.admin.AdminTestCase;
+import org.opends.server.admin.TestCfg;
+import org.opends.server.admin.TestChildCfg;
+import org.opends.server.admin.TestParentCfg;
+import org.opends.server.config.ConfigException;
+import org.opends.server.core.DirectoryServer;
+import org.opends.server.types.ConfigChangeResult;
+import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+/**
+ * Test cases for default behavior on the server-side.
+ */
+public final class DefaultBehaviorTest extends AdminTestCase {
+
+ /**
+ * A test child add listener.
+ */
+ private static class AddListener implements ConfigurationAddListener<TestChildCfg> {
+
+ // The child configuration that was added.
+ private TestChildCfg child;
+
+ /**
+ * Creates a new add listener.
+ */
+ public AddListener() {
+ // No implementation required.
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ConfigChangeResult applyConfigurationAdd(TestChildCfg configuration) {
+ return new ConfigChangeResult(ResultCode.SUCCESS, false);
+ }
+
+ /**
+ * Gets the child configuration checking that it has the expected name.
+ *
+ * @param expectedName
+ * The child's expected name.
+ * @return Returns the child configuration.
+ */
+ public TestChildCfg getChild(String expectedName) {
+ Assert.assertNotNull(child);
+ Assert.assertEquals(child.dn().getRDN().getAttributeValue(0).getValue().toString(), expectedName);
+ return child;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isConfigurationAddAcceptable(TestChildCfg configuration, List<Message> unacceptableReasons) {
+ child = configuration;
+ return true;
+ }
+
+ }
+
+ /**
+ * A test child change listener.
+ */
+ private static class ChangeListener implements ConfigurationChangeListener<TestChildCfg> {
+
+ // The child configuration that was changed.
+ private TestChildCfg child;
+
+ /**
+ * Creates a new change listener.
+ */
+ public ChangeListener() {
+ // No implementation required.
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ConfigChangeResult applyConfigurationChange(TestChildCfg configuration) {
+ return new ConfigChangeResult(ResultCode.SUCCESS, false);
+ }
+
+ /**
+ * Gets the child configuration checking that it has the expected name.
+ *
+ * @param expectedName
+ * The child's expected name.
+ * @return Returns the child configuration.
+ */
+ public TestChildCfg getChild(String expectedName) {
+ Assert.assertNotNull(child);
+ Assert.assertEquals(child.dn().getRDN().getAttributeValue(0).getValue().toString(), expectedName);
+ return child;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isConfigurationChangeAcceptable(TestChildCfg configuration, List<Message> unacceptableReasons) {
+ child = configuration;
+ return true;
+ }
+
+ }
+
+ // Test child 1 LDIF.
+ private static final String[] TEST_CHILD_1 = new String[] {
+ "dn: cn=test child 1,cn=test children,cn=test parent 1,cn=test parents,cn=config", "objectclass: top",
+ "objectclass: ds-cfg-test-child-dummy", "cn: test child 1", "ds-cfg-enabled: true",
+ "ds-cfg-java-class: org.opends.server.extensions.UserDefinedVirtualAttributeProvider",
+ "ds-cfg-attribute-type: description", "ds-cfg-conflict-behavior: virtual-overrides-real" };
+
+ // Test child 2 LDIF.
+ private static final String[] TEST_CHILD_2 = new String[] {
+ "dn: cn=test child 2,cn=test children,cn=test parent 1,cn=test parents,cn=config", "objectclass: top",
+ "objectclass: ds-cfg-test-child-dummy", "cn: test child 2", "ds-cfg-enabled: true",
+ "ds-cfg-java-class: org.opends.server.extensions.UserDefinedVirtualAttributeProvider",
+ "ds-cfg-attribute-type: description", "ds-cfg-conflict-behavior: virtual-overrides-real",
+ "ds-cfg-base-dn: dc=default value c2v1,dc=com", "ds-cfg-base-dn: dc=default value c2v2,dc=com" };
+
+ // Test child 3 LDIF.
+ private static final String[] TEST_CHILD_3 = new String[] {
+ "dn: cn=test child 3,cn=test children,cn=test parent 1,cn=test parents,cn=config", "objectclass: top",
+ "objectclass: ds-cfg-test-child-dummy", "cn: test child 3", "ds-cfg-enabled: true",
+ "ds-cfg-java-class: org.opends.server.extensions.UserDefinedVirtualAttributeProvider",
+ "ds-cfg-attribute-type: description", "ds-cfg-conflict-behavior: virtual-overrides-real",
+ "ds-cfg-base-dn: dc=default value c3v1,dc=com", "ds-cfg-base-dn: dc=default value c3v2,dc=com",
+ "ds-cfg-group-dn: dc=default value c3v3,dc=com", "ds-cfg-group-dn: dc=default value c3v4,dc=com" };
+
+ // Test child 4 LDIF.
+ private static final String[] TEST_CHILD_4 = new String[] {
+ "dn: cn=test child 4,cn=test children,cn=test parent 2,cn=test parents,cn=config", "objectclass: top",
+ "objectclass: ds-cfg-test-child-dummy", "cn: test child 4", "ds-cfg-enabled: true",
+ "ds-cfg-java-class: org.opends.server.extensions.UserDefinedVirtualAttributeProvider",
+ "ds-cfg-attribute-type: description", "ds-cfg-conflict-behavior: virtual-overrides-real" };
+
+ // Test LDIF.
+ private static final String[] TEST_LDIF = new String[] {
+ // Base entries.
+ "dn: cn=test parents,cn=config",
+ "objectclass: top",
+ "objectclass: ds-cfg-branch",
+ "cn: test parents",
+ "",
+ // Parent 1 - uses default values for
+ // optional-multi-valued-dn-property.
+ "dn: cn=test parent 1,cn=test parents,cn=config",
+ "objectclass: top",
+ "objectclass: ds-cfg-test-parent-dummy",
+ "cn: test parent 1",
+ "ds-cfg-enabled: true",
+ "ds-cfg-java-class: org.opends.server.extensions.UserDefinedVirtualAttributeProvider",
+ "ds-cfg-attribute-type: description",
+ "ds-cfg-conflict-behavior: virtual-overrides-real",
+ "",
+ // Parent 2 - overrides default values for
+ // optional-multi-valued-dn-property.
+ "dn: cn=test parent 2,cn=test parents,cn=config", "objectclass: top",
+ "objectclass: ds-cfg-test-parent-dummy", "cn: test parent 2", "ds-cfg-enabled: true",
+ "ds-cfg-java-class: org.opends.server.extensions.UserDefinedVirtualAttributeProvider",
+ "ds-cfg-attribute-type: description", "ds-cfg-conflict-behavior: virtual-overrides-real",
+ "ds-cfg-base-dn: dc=default value p2v1,dc=com",
+ "ds-cfg-base-dn: dc=default value p2v2,dc=com",
+ "",
+ // Child base entries.
+ "dn:cn=test children,cn=test parent 1,cn=test parents,cn=config", "objectclass: top",
+ "objectclass: ds-cfg-branch", "cn: test children", "",
+ "dn:cn=test children,cn=test parent 2,cn=test parents,cn=config", "objectclass: top",
+ "objectclass: ds-cfg-branch", "cn: test children", "" };
+
+ // JNDI LDAP context.
+ private JNDIDirContextAdaptor adaptor = null;
+
+ /**
+ * Sets up tests
+ *
+ * @throws Exception
+ * If the server could not be initialized.
+ */
+ @BeforeClass
+ public void setUp() throws Exception {
+ // This test suite depends on having the schema available, so
+ // we'll start the server.
+ TestCaseUtils.startServer();
+ TestCfg.setUp();
+
+ // Add test managed objects.
+ TestCaseUtils.addEntries(TEST_LDIF);
+ }
+
+ /**
+ * Tears down test environment.
+ *
+ * @throws Exception
+ * If the test entries could not be removed.
+ */
+ @AfterClass
+ public void tearDown() throws Exception {
+ TestCfg.cleanup();
+
+ // Remove test entries.
+ deleteSubtree("cn=test parents,cn=config");
+ }
+
+ /**
+ * Tests that children have correct values when accessed through an add
+ * listener.
+ *
+ * @throws Exception
+ * If the test unexpectedly fails.
+ */
+ @Test
+ public void testAddListenerChildValues1() throws Exception {
+ TestParentCfg parent = getParent("test parent 1");
+ AddListener listener = new AddListener();
+ parent.addTestChildAddListener(listener);
+
+ try {
+ // Add the entry.
+ TestCaseUtils.addEntry(TEST_CHILD_1);
+ try {
+ assertChild1(listener.getChild("test child 1"));
+ } finally {
+ deleteSubtree("cn=test child 1,cn=test children,cn=test parent 1,cn=test parents,cn=config");
+ }
+ } finally {
+ parent.removeTestChildAddListener(listener);
+ }
+ }
+
+ /**
+ * Tests that children have correct values when accessed through an add
+ * listener.
+ *
+ * @throws Exception
+ * If the test unexpectedly fails.
+ */
+ @Test
+ public void testAddListenerChildValues2() throws Exception {
+ TestParentCfg parent = getParent("test parent 1");
+ AddListener listener = new AddListener();
+ parent.addTestChildAddListener(listener);
+
+ try {
+ // Add the entry.
+ TestCaseUtils.addEntry(TEST_CHILD_2);
+ try {
+ assertChild2(listener.getChild("test child 2"));
+ } finally {
+ deleteSubtree("cn=test child 2,cn=test children,cn=test parent 1,cn=test parents,cn=config");
+ }
+ } finally {
+ parent.removeTestChildAddListener(listener);
+ }
+ }
+
+ /**
+ * Tests that children have correct values when accessed through an add
+ * listener.
+ *
+ * @throws Exception
+ * If the test unexpectedly fails.
+ */
+ @Test
+ public void testAddListenerChildValues3() throws Exception {
+ TestParentCfg parent = getParent("test parent 1");
+ AddListener listener = new AddListener();
+ parent.addTestChildAddListener(listener);
+
+ try {
+ // Add the entry.
+ TestCaseUtils.addEntry(TEST_CHILD_3);
+ try {
+ assertChild3(listener.getChild("test child 3"));
+ } finally {
+ deleteSubtree("cn=test child 3,cn=test children,cn=test parent 1,cn=test parents,cn=config");
+ }
+ } finally {
+ parent.removeTestChildAddListener(listener);
+ }
+ }
+
+ /**
+ * Tests that children have correct values when accessed through an add
+ * listener.
+ *
+ * @throws Exception
+ * If the test unexpectedly fails.
+ */
+ @Test
+ public void testAddListenerChildValues4() throws Exception {
+ TestParentCfg parent = getParent("test parent 2");
+ AddListener listener = new AddListener();
+ parent.addTestChildAddListener(listener);
+
+ try {
+ // Add the entry.
+ TestCaseUtils.addEntry(TEST_CHILD_4);
+ try {
+ assertChild4(listener.getChild("test child 4"));
+ } finally {
+ deleteSubtree("cn=test child 4,cn=test children,cn=test parent 2,cn=test parents,cn=config");
+ }
+ } finally {
+ parent.removeTestChildAddListener(listener);
+ }
+ }
+
+ /**
+ * Tests that children have correct values when accessed through a change
+ * listener. This test replaces the defaulted properties with real values.
+ *
+ * @throws Exception
+ * If the test unexpectedly fails.
+ */
+ @Test
+ public void testChangeListenerChildValues1() throws Exception {
+ TestParentCfg parent = getParent("test parent 1");
+
+ try {
+ // Add the entry.
+ TestCaseUtils.addEntry(TEST_CHILD_1);
+ TestChildCfg child = parent.getTestChild("test child 1");
+ ChangeListener listener = new ChangeListener();
+ child.addChangeListener(listener);
+
+ // Now modify it.
+ String[] changes = new String[] {
+ "dn: cn=test child 1,cn=test children,cn=test parent 1,cn=test parents,cn=config",
+ "changetype: modify", "replace: ds-cfg-base-dn", "ds-cfg-base-dn: dc=new value 1,dc=com",
+ "ds-cfg-base-dn: dc=new value 2,dc=com", "-", "replace: ds-cfg-group-dn",
+ "ds-cfg-group-dn: dc=new value 3,dc=com", "ds-cfg-group-dn: dc=new value 4,dc=com" };
+ TestCaseUtils.applyModifications(true, changes);
+
+ // Make sure that the change listener was notified and the
+ // modified child contains the correct values.
+ child = listener.getChild("test child 1");
+
+ Assert.assertEquals(child.getMandatoryClassProperty(),
+ "org.opends.server.extensions.UserDefinedVirtualAttributeProvider");
+ Assert.assertEquals(child.getMandatoryReadOnlyAttributeTypeProperty(),
+ DirectoryServer.getAttributeType("description"));
+ assertDNSetEquals(child.getOptionalMultiValuedDNProperty1(), "dc=new value 1,dc=com",
+ "dc=new value 2,dc=com");
+ assertDNSetEquals(child.getOptionalMultiValuedDNProperty2(), "dc=new value 3,dc=com",
+ "dc=new value 4,dc=com");
+ } finally {
+ deleteSubtree("cn=test child 1,cn=test children,cn=test parent 1,cn=test parents,cn=config");
+ }
+ }
+
+ /**
+ * Tests that children have correct values when accessed through a change
+ * listener. This test makes sure that default values inherited from within
+ * the modified component itself behave as expected.
+ *
+ * @throws Exception
+ * If the test unexpectedly fails.
+ */
+ @Test
+ public void testChangeListenerChildValues2() throws Exception {
+ TestParentCfg parent = getParent("test parent 1");
+
+ try {
+ // Add the entry.
+ TestCaseUtils.addEntry(TEST_CHILD_1);
+ TestChildCfg child = parent.getTestChild("test child 1");
+ ChangeListener listener = new ChangeListener();
+ child.addChangeListener(listener);
+
+ // Now modify it.
+ String[] changes = new String[] {
+ "dn: cn=test child 1,cn=test children,cn=test parent 1,cn=test parents,cn=config",
+ "changetype: modify", "replace: ds-cfg-base-dn", "ds-cfg-base-dn: dc=new value 1,dc=com",
+ "ds-cfg-base-dn: dc=new value 2,dc=com" };
+ TestCaseUtils.applyModifications(true, changes);
+
+ // Make sure that the change listener was notified and the
+ // modified child contains the correct values.
+ child = listener.getChild("test child 1");
+
+ Assert.assertEquals(child.getMandatoryClassProperty(),
+ "org.opends.server.extensions.UserDefinedVirtualAttributeProvider");
+ Assert.assertEquals(child.getMandatoryReadOnlyAttributeTypeProperty(),
+ DirectoryServer.getAttributeType("description"));
+ assertDNSetEquals(child.getOptionalMultiValuedDNProperty1(), "dc=new value 1,dc=com",
+ "dc=new value 2,dc=com");
+ assertDNSetEquals(child.getOptionalMultiValuedDNProperty2(), "dc=new value 1,dc=com",
+ "dc=new value 2,dc=com");
+ } finally {
+ deleteSubtree("cn=test child 1,cn=test children,cn=test parent 1,cn=test parents,cn=config");
+ }
+ }
+
+ /**
+ * Tests that children have correct values when accessed through a change
+ * listener. This test makes sure that default values inherited from outside
+ * the modified component behave as expected.
+ *
+ * @throws Exception
+ * If the test unexpectedly fails.
+ */
+ @Test
+ public void testChangeListenerChildValues3() throws Exception {
+ TestParentCfg parent = getParent("test parent 1");
+
+ try {
+ // Add the entry.
+ TestCaseUtils.addEntry(TEST_CHILD_1);
+ TestChildCfg child = parent.getTestChild("test child 1");
+ ChangeListener listener = new ChangeListener();
+ child.addChangeListener(listener);
+
+ // Now modify it.
+ String[] changes = new String[] {
+ "dn: cn=test child 1,cn=test children,cn=test parent 1,cn=test parents,cn=config",
+ "changetype: modify", "replace: ds-cfg-group-dn", "ds-cfg-group-dn: dc=new value 1,dc=com",
+ "ds-cfg-group-dn: dc=new value 2,dc=com" };
+ TestCaseUtils.applyModifications(true, changes);
+
+ // Make sure that the change listener was notified and the
+ // modified child contains the correct values.
+ child = listener.getChild("test child 1");
+
+ Assert.assertEquals(child.getMandatoryClassProperty(),
+ "org.opends.server.extensions.UserDefinedVirtualAttributeProvider");
+ Assert.assertEquals(child.getMandatoryReadOnlyAttributeTypeProperty(),
+ DirectoryServer.getAttributeType("description"));
+ assertDNSetEquals(child.getOptionalMultiValuedDNProperty1(), "dc=domain1,dc=com", "dc=domain2,dc=com",
+ "dc=domain3,dc=com");
+ assertDNSetEquals(child.getOptionalMultiValuedDNProperty2(), "dc=new value 1,dc=com",
+ "dc=new value 2,dc=com");
+ } finally {
+ deleteSubtree("cn=test child 1,cn=test children,cn=test parent 1,cn=test parents,cn=config");
+ }
+ }
+
+ /**
+ * Tests that children have correct values when accessed through a change
+ * listener. This test makes sure that a component is notified when the
+ * default values it inherits from another component are modified.
+ *
+ * @throws Exception
+ * If the test unexpectedly fails.
+ */
+ @Test
+ public void testChangeListenerChildValues4() throws Exception {
+ TestParentCfg parent = getParent("test parent 1");
+
+ try {
+ // Add the entry.
+ TestCaseUtils.addEntry(TEST_CHILD_1);
+ TestChildCfg child = parent.getTestChild("test child 1");
+ ChangeListener listener = new ChangeListener();
+ child.addChangeListener(listener);
+
+ // Now modify the parent.
+ String[] changes = new String[] { "dn: cn=test parent 1,cn=test parents,cn=config", "changetype: modify",
+ "replace: ds-cfg-base-dn", "ds-cfg-base-dn: dc=new value 1,dc=com",
+ "ds-cfg-base-dn: dc=new value 2,dc=com" };
+ TestCaseUtils.applyModifications(true, changes);
+
+ // Make sure that the change listener was notified and the
+ // modified child contains the correct values.
+ child = listener.getChild("test child 1");
+
+ Assert.assertEquals(child.getMandatoryClassProperty(),
+ "org.opends.server.extensions.UserDefinedVirtualAttributeProvider");
+ Assert.assertEquals(child.getMandatoryReadOnlyAttributeTypeProperty(),
+ DirectoryServer.getAttributeType("description"));
+ assertDNSetEquals(child.getOptionalMultiValuedDNProperty1(), "dc=new value 1,dc=com",
+ "dc=new value 2,dc=com");
+ assertDNSetEquals(child.getOptionalMultiValuedDNProperty2(), "dc=new value 1,dc=com",
+ "dc=new value 2,dc=com");
+ } finally {
+ deleteSubtree("cn=test child 1,cn=test children,cn=test parent 1,cn=test parents,cn=config");
+
+ // Undo the modifications.
+ String[] changes = new String[] { "dn: cn=test parent 1,cn=test parents,cn=config", "changetype: modify",
+ "delete: ds-cfg-base-dn" };
+ TestCaseUtils.applyModifications(true, changes);
+ }
+ }
+
+ /**
+ * Tests that children have correct values.
+ *
+ * @throws Exception
+ * If the test unexpectedly fails.
+ */
+ @Test
+ public void testChildValues1() throws Exception {
+ // Add the entry.
+ TestCaseUtils.addEntry(TEST_CHILD_1);
+
+ try {
+ TestParentCfg parent = getParent("test parent 1");
+ assertChild1(parent.getTestChild("test child 1"));
+ } finally {
+ deleteSubtree("cn=test child 1,cn=test children,cn=test parent 1,cn=test parents,cn=config");
+ }
+ }
+
+ /**
+ * Tests that children have correct values.
+ *
+ * @throws Exception
+ * If the test unexpectedly fails.
+ */
+ @Test
+ public void testChildValues2() throws Exception {
+ // Add the entry.
+ TestCaseUtils.addEntry(TEST_CHILD_2);
+
+ try {
+ TestParentCfg parent = getParent("test parent 1");
+ assertChild2(parent.getTestChild("test child 2"));
+ } finally {
+ deleteSubtree("cn=test child 2,cn=test children,cn=test parent 1,cn=test parents,cn=config");
+ }
+ }
+
+ /**
+ * Tests that children have correct values.
+ *
+ * @throws Exception
+ * If the test unexpectedly fails.
+ */
+ @Test
+ public void testChildValues3() throws Exception {
+ // Add the entry.
+ TestCaseUtils.addEntry(TEST_CHILD_3);
+
+ try {
+ TestParentCfg parent = getParent("test parent 1");
+ assertChild3(parent.getTestChild("test child 3"));
+ } finally {
+ deleteSubtree("cn=test child 3,cn=test children,cn=test parent 1,cn=test parents,cn=config");
+ }
+ }
+
+ /**
+ * Tests that children have correct values.
+ *
+ * @throws Exception
+ * If the test unexpectedly fails.
+ */
+ @Test
+ public void testChildValues4() throws Exception {
+ // Add the entry.
+ TestCaseUtils.addEntry(TEST_CHILD_4);
+
+ try {
+ TestParentCfg parent = getParent("test parent 2");
+ assertChild4(parent.getTestChild("test child 4"));
+ } finally {
+ deleteSubtree("cn=test child 4,cn=test children,cn=test parent 2,cn=test parents,cn=config");
+ }
+ }
+
+ /**
+ * Tests that parent 1 has correct values.
+ *
+ * @throws Exception
+ * If the test unexpectedly fails.
+ */
+ @Test
+ public void testParentValues1() throws Exception {
+ TestParentCfg parent = getParent("test parent 1");
+
+ Assert.assertEquals(parent.getMandatoryClassProperty(),
+ "org.opends.server.extensions.UserDefinedVirtualAttributeProvider");
+ Assert.assertEquals(parent.getMandatoryReadOnlyAttributeTypeProperty(),
+ DirectoryServer.getAttributeType("description"));
+ assertDNSetEquals(parent.getOptionalMultiValuedDNProperty(), "dc=domain1,dc=com", "dc=domain2,dc=com",
+ "dc=domain3,dc=com");
+ }
+
+ /**
+ * Tests that parent 2 has correct values.
+ *
+ * @throws Exception
+ * If the test unexpectedly fails.
+ */
+ @Test
+ public void testParentValues2() throws Exception {
+ TestParentCfg parent = getParent("test parent 2");
+
+ Assert.assertEquals(parent.getMandatoryClassProperty(),
+ "org.opends.server.extensions.UserDefinedVirtualAttributeProvider");
+ Assert.assertEquals(parent.getMandatoryReadOnlyAttributeTypeProperty(),
+ DirectoryServer.getAttributeType("description"));
+ assertDNSetEquals(parent.getOptionalMultiValuedDNProperty(), "dc=default value p2v1,dc=com",
+ "dc=default value p2v2,dc=com");
+ }
+
+ // Assert that the values of child 1 are correct.
+ private void assertChild1(TestChildCfg child) {
+ Assert.assertEquals(child.getMandatoryClassProperty(),
+ "org.opends.server.extensions.UserDefinedVirtualAttributeProvider");
+ Assert.assertEquals(child.getMandatoryReadOnlyAttributeTypeProperty(),
+ DirectoryServer.getAttributeType("description"));
+ assertDNSetEquals(child.getOptionalMultiValuedDNProperty1(), "dc=domain1,dc=com", "dc=domain2,dc=com",
+ "dc=domain3,dc=com");
+ assertDNSetEquals(child.getOptionalMultiValuedDNProperty2(), "dc=domain1,dc=com", "dc=domain2,dc=com",
+ "dc=domain3,dc=com");
+ }
+
+ // Assert that the values of child 2 are correct.
+ private void assertChild2(TestChildCfg child) {
+ Assert.assertEquals(child.getMandatoryClassProperty(),
+ "org.opends.server.extensions.UserDefinedVirtualAttributeProvider");
+ Assert.assertEquals(child.getMandatoryReadOnlyAttributeTypeProperty(),
+ DirectoryServer.getAttributeType("description"));
+ assertDNSetEquals(child.getOptionalMultiValuedDNProperty1(), "dc=default value c2v1,dc=com",
+ "dc=default value c2v2,dc=com");
+ assertDNSetEquals(child.getOptionalMultiValuedDNProperty2(), "dc=default value c2v1,dc=com",
+ "dc=default value c2v2,dc=com");
+ }
+
+ // Assert that the values of child 3 are correct.
+ private void assertChild3(TestChildCfg child) {
+ Assert.assertEquals(child.getMandatoryClassProperty(),
+ "org.opends.server.extensions.UserDefinedVirtualAttributeProvider");
+ Assert.assertEquals(child.getMandatoryReadOnlyAttributeTypeProperty(),
+ DirectoryServer.getAttributeType("description"));
+ assertDNSetEquals(child.getOptionalMultiValuedDNProperty1(), "dc=default value c3v1,dc=com",
+ "dc=default value c3v2,dc=com");
+ assertDNSetEquals(child.getOptionalMultiValuedDNProperty2(), "dc=default value c3v3,dc=com",
+ "dc=default value c3v4,dc=com");
+ }
+
+ // Assert that the values of child 4 are correct.
+ private void assertChild4(TestChildCfg child) {
+ Assert.assertEquals(child.getMandatoryClassProperty(),
+ "org.opends.server.extensions.UserDefinedVirtualAttributeProvider");
+ Assert.assertEquals(child.getMandatoryReadOnlyAttributeTypeProperty(),
+ DirectoryServer.getAttributeType("description"));
+ assertDNSetEquals(child.getOptionalMultiValuedDNProperty1(), "dc=default value p2v1,dc=com",
+ "dc=default value p2v2,dc=com");
+ assertDNSetEquals(child.getOptionalMultiValuedDNProperty2(), "dc=default value p2v1,dc=com",
+ "dc=default value p2v2,dc=com");
+ }
+
+ // Asserts that the actual set of DNs contains the expected values.
+ private void assertDNSetEquals(SortedSet<DN> actual, String... expected) {
+ String[] actualStrings = new String[actual.size()];
+ int i = 0;
+ for (DN dn : actual) {
+ actualStrings[i] = dn.toString();
+ i++;
+ }
+ Assert.assertEqualsNoOrder(actualStrings, expected);
+ }
+
+ // Deletes the named sub-tree.
+ private void deleteSubtree(String dn) throws Exception {
+ getAdaptor().deleteSubtree(new LdapName(dn));
+ }
+
+ // Gets the JNDI connection for the test server instance.
+ private synchronized JNDIDirContextAdaptor getAdaptor() throws Exception {
+ if (adaptor == null) {
+ adaptor = JNDIDirContextAdaptor.simpleSSLBind("127.0.0.1", TestCaseUtils.getServerAdminPort(),
+ "cn=directory manager", "password");
+ }
+ return adaptor;
+ }
+
+ // Gets the named parent configuration.
+ private TestParentCfg getParent(String name) throws IllegalArgumentException, ConfigException {
+ ServerManagedObject<RootCfg> root = serverContext.getRootConfigurationManagedObject();
+ TestParentCfg parent = root.getChild(TestCfg.getTestOneToManyParentRelationDefinition(), name)
+ .getConfiguration();
+ return parent;
+ }
+}
diff --git a/opendj-sdk/opendj-admin/src/test/java/org/opends/server/admin/server/ListenerTest.java b/opendj-sdk/opendj-admin/src/test/java/org/opends/server/admin/server/ListenerTest.java
new file mode 100644
index 0000000..cff57d5
--- /dev/null
+++ b/opendj-sdk/opendj-admin/src/test/java/org/opends/server/admin/server/ListenerTest.java
@@ -0,0 +1,275 @@
+/*
+ * 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 legal-notices/CDDLv1_0.txt
+ * or http://forgerock.org/license/CDDLv1.0.html.
+ * 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 legal-notices/CDDLv1_0.txt.
+ * 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
+ *
+ *
+ * Copyright 2007-2008 Sun Microsystems, Inc.
+ */
+package org.opends.server.admin.server;
+
+import static org.fest.assertions.Assertions.*;
+import static org.mockito.Mockito.*;
+
+import java.util.Arrays;
+import org.forgerock.opendj.admin.server.RootCfg;
+import org.forgerock.opendj.ldap.DN;
+import org.forgerock.opendj.ldap.Entry;
+import org.forgerock.opendj.ldap.TestCaseUtils;
+import org.mockito.ArgumentCaptor;
+import org.opends.server.admin.AdminTestCase;
+import org.opends.server.admin.TestCfg;
+import org.opends.server.admin.TestParentCfg;
+import org.opends.server.api.ConfigAddListener;
+import org.opends.server.api.ConfigChangeListener;
+import org.opends.server.api.ConfigDeleteListener;
+import org.opends.server.config.ConfigException;
+import org.opends.server.config.ConfigurationRepository;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+
+@SuppressWarnings({"javadoc", "rawtypes", "unchecked"})
+public class ListenerTest extends AdminTestCase {
+
+ private static final DN ROOT_CONFIG_DN = DN.valueOf("cn=config");
+ private static final DN TEST_PARENTS_DN = DN.valueOf("cn=test parents,cn=config");
+
+ @BeforeClass
+ public void setUp() throws Exception {
+ disableClassValidationForProperties();
+ TestCfg.setUp();
+ }
+
+ @AfterClass
+ public void tearDown() throws Exception {
+ TestCfg.cleanup();
+ }
+
+ private Entry getTestParentEntry() throws Exception {
+ return TestCaseUtils.makeEntry(
+ "dn: cn=test parents,cn=config",
+ "objectclass: top",
+ "objectclass: ds-cfg-branch",
+ "cn: test parents");
+ }
+
+ /**
+ * Create a mock of ConfigurationRepository with provided DNs registered.
+ */
+ private ConfigurationRepository createConfigRepositoryWithDNs(DN...dns) throws ConfigException {
+ ConfigurationRepository configRepository = mock(ConfigurationRepository.class);
+ for (DN dn : dns) {
+ when(configRepository.hasEntry(dn)).thenReturn(true);
+ }
+ return configRepository;
+ }
+
+ /** Register a listener for test parent entry and return the actual registered listener */
+ private ConfigAddListener registerAddListenerForTestParent(ConfigurationRepository configRepository,
+ ServerManagedObject<RootCfg> root, ConfigurationAddListener<TestParentCfg> parentListener)
+ throws Exception {
+ root.registerAddListener(TestCfg.getTestOneToManyParentRelationDefinition(), parentListener);
+
+ ArgumentCaptor<ConfigAddListener> registered = ArgumentCaptor.forClass(ConfigAddListener.class);
+ verify(configRepository).registerAddListener(eq(TEST_PARENTS_DN), registered.capture());
+ return registered.getValue();
+ }
+
+ /** Register a listener for test parent entry in delayed scenario and return the actual registered listener */
+ private DelayedConfigAddListener registerAddListenerForTestParentDelayed(ConfigurationRepository configRepository,
+ ServerManagedObject<RootCfg> root, ConfigurationAddListener<TestParentCfg> parentListener)
+ throws Exception {
+ root.registerAddListener(TestCfg.getTestOneToManyParentRelationDefinition(), parentListener);
+
+ ArgumentCaptor<DelayedConfigAddListener> registered = ArgumentCaptor.forClass(DelayedConfigAddListener.class);
+ verify(configRepository).registerAddListener(eq(ROOT_CONFIG_DN), registered.capture());
+ return registered.getValue();
+ }
+
+ @Test
+ public void testRegisterAddListenerWithInstantiableRelationImmediate() throws Exception {
+ ConfigurationRepository configRepository = createConfigRepositoryWithDNs(ROOT_CONFIG_DN, TEST_PARENTS_DN);
+ ServerManagementContext context = new ServerManagementContext(configRepository);
+ ServerManagedObject<RootCfg> root = context.getRootConfigurationManagedObject();
+
+ root.registerAddListener(TestCfg.getTestOneToManyParentRelationDefinition(),
+ mock(ConfigurationAddListener.class));
+
+ verify(configRepository).registerAddListener(eq(TEST_PARENTS_DN),
+ isA(ConfigAddListener.class));
+ }
+
+ @Test
+ public void testRegisterAddListenerWithInstantiableRelationDelayed() throws Exception {
+ ConfigurationRepository configRepository = createConfigRepositoryWithDNs(ROOT_CONFIG_DN);
+ ServerManagementContext context = new ServerManagementContext(configRepository);
+ ServerManagedObject<RootCfg> root = context.getRootConfigurationManagedObject();
+
+ ConfigurationAddListener<TestParentCfg> parentListener = mock(ConfigurationAddListener.class);
+ root.registerAddListener(TestCfg.getTestOneToManyParentRelationDefinition(), parentListener);
+
+ ArgumentCaptor<DelayedConfigAddListener> registered = ArgumentCaptor.forClass(DelayedConfigAddListener.class);
+ verify(configRepository).registerAddListener(eq(ROOT_CONFIG_DN), registered.capture());
+ // check that actual listener is the one provided to the root
+ ConfigurationAddListener<?> actualListener =
+ ((ServerManagedObjectAddListenerAdaptor<?>)
+ ((ConfigAddListenerAdaptor<?>) registered.getValue().getDelayedAddListener()).
+ getServerManagedObjectAddListener()).getConfigurationAddListener();
+ assertThat(actualListener).isEqualTo(parentListener);
+ }
+
+ @Test
+ public void testRegisterAddListenerWithInstantiableRelationDelayedThenActualized() throws Exception {
+ ConfigurationRepository configRepository = createConfigRepositoryWithDNs(ROOT_CONFIG_DN);
+ ServerManagementContext context = new ServerManagementContext(configRepository);
+ ServerManagedObject<RootCfg> root = context.getRootConfigurationManagedObject();
+
+ // register a listener to root
+ ConfigurationAddListener<TestParentCfg> parentListener = mock(ConfigurationAddListener.class);
+ root.registerAddListener(TestCfg.getTestOneToManyParentRelationDefinition(), parentListener);
+
+ // get the delayed listener registered to configuration repository
+ ArgumentCaptor<DelayedConfigAddListener> registered = ArgumentCaptor.forClass(DelayedConfigAddListener.class);
+ verify(configRepository).registerAddListener(eq(ROOT_CONFIG_DN), registered.capture());
+
+ // now simulate the add of target entry
+ String parentDN = "cn=test parents,cn=config";
+ when(configRepository.hasEntry(DN.valueOf(parentDN))).thenReturn(true);
+ registered.getValue().applyConfigurationAdd(getTestParentEntry());
+
+ // check that listener is added for target entry and deleted for its parent entry
+ ConfigAddListenerAdaptor listener =
+ (ConfigAddListenerAdaptor<?>) registered.getValue().getDelayedAddListener();
+ verify(configRepository).registerAddListener(DN.valueOf(parentDN), listener);
+ verify(configRepository).deregisterAddListener(ROOT_CONFIG_DN, registered.getValue());
+ }
+
+ @Test
+ public void testRegisterAddListenerWithOptionalRelation() throws Exception {
+ ConfigurationRepository configRepository = createConfigRepositoryWithDNs(ROOT_CONFIG_DN);
+ ServerManagementContext context = new ServerManagementContext(configRepository);
+ ServerManagedObject<RootCfg> root = context.getRootConfigurationManagedObject();
+
+ root.registerAddListener(TestCfg.getTestOneToZeroOrOneParentRelationDefinition(),
+ mock(ConfigurationAddListener.class));
+
+ verify(configRepository).registerAddListener(eq(ROOT_CONFIG_DN),
+ isA(ConfigAddListener.class));
+ }
+
+ @Test
+ public void testRegisterDeleteListenerWithInstantiableRelationImmediate() throws Exception {
+ ConfigurationRepository configRepository = createConfigRepositoryWithDNs(ROOT_CONFIG_DN, TEST_PARENTS_DN);
+ ServerManagementContext context = new ServerManagementContext(configRepository);
+ ServerManagedObject<RootCfg> root = context.getRootConfigurationManagedObject();
+
+ root.registerDeleteListener(TestCfg.getTestOneToManyParentRelationDefinition(),
+ mock(ConfigurationDeleteListener.class));
+
+ verify(configRepository).registerDeleteListener(eq(TEST_PARENTS_DN),
+ isA(ConfigDeleteListener.class));
+ }
+
+ @Test
+ public void testRegisterDeleteListenerWithInstantiableRelationDelayed() throws Exception {
+ ConfigurationRepository configRepository = createConfigRepositoryWithDNs(ROOT_CONFIG_DN);
+ ServerManagementContext context = new ServerManagementContext(configRepository);
+ ServerManagedObject<RootCfg> root = context.getRootConfigurationManagedObject();
+
+ ConfigurationDeleteListener<TestParentCfg> parentListener = mock(ConfigurationDeleteListener.class);
+ root.registerDeleteListener(TestCfg.getTestOneToManyParentRelationDefinition(), parentListener);
+
+ ArgumentCaptor<DelayedConfigAddListener> argument = ArgumentCaptor.forClass(DelayedConfigAddListener.class);
+ verify(configRepository).registerAddListener(eq(ROOT_CONFIG_DN), argument.capture());
+ // check that actual listener is the one provided to the root
+ ConfigurationDeleteListener actualListener =
+ ((ServerManagedObjectDeleteListenerAdaptor)
+ ((ConfigDeleteListenerAdaptor)argument.getValue().getDelayedDeleteListener()).
+ getServerManagedObjectDeleteListener()).getConfigurationDeleteListener();
+ assertThat(actualListener).isEqualTo(parentListener);
+ }
+
+ @Test
+ public void testRegisterDeleteListenerWithOptionalRelation() throws Exception {
+ ConfigurationRepository configRepository = createConfigRepositoryWithDNs(ROOT_CONFIG_DN);
+ ServerManagementContext context = new ServerManagementContext(configRepository);
+ ServerManagedObject<RootCfg> root = context.getRootConfigurationManagedObject();
+
+ root.registerDeleteListener(TestCfg.getTestOneToZeroOrOneParentRelationDefinition(),
+ mock(ConfigurationDeleteListener.class));
+
+ verify(configRepository).registerDeleteListener(eq(ROOT_CONFIG_DN),
+ isA(ConfigDeleteListener.class));
+ }
+
+ @Test
+ public void testRegisterChangeListener() throws Exception {
+ ConfigurationRepository configRepository = createConfigRepositoryWithDNs(ROOT_CONFIG_DN);
+ ServerManagementContext context = new ServerManagementContext(configRepository);
+ ServerManagedObject<RootCfg> root = context.getRootConfigurationManagedObject();
+ root.setConfigDN(ROOT_CONFIG_DN);
+
+ root.registerChangeListener(mock(ConfigurationChangeListener.class));
+
+ verify(configRepository).registerChangeListener(eq(ROOT_CONFIG_DN),
+ isA(ConfigChangeListener.class));
+ }
+
+ @Test
+ public void testDeregisterAddListenerWithInstantiableRelationImmediate() throws Exception {
+ // arrange
+ ConfigurationRepository configRepository = createConfigRepositoryWithDNs(ROOT_CONFIG_DN, TEST_PARENTS_DN);
+ ServerManagementContext context = new ServerManagementContext(configRepository);
+ ServerManagedObject<RootCfg> root = context.getRootConfigurationManagedObject();
+
+ ConfigurationAddListener<TestParentCfg> parentListener = mock(ConfigurationAddListener.class);
+ ConfigAddListener registeredListener =
+ registerAddListenerForTestParent(configRepository, root, parentListener);
+ when(configRepository.getAddListeners(TEST_PARENTS_DN)).thenReturn(Arrays.asList(registeredListener));
+
+ // act
+ root.deregisterAddListener(TestCfg.getTestOneToManyParentRelationDefinition(), parentListener);
+
+ // assert
+ verify(configRepository).deregisterAddListener(eq(TEST_PARENTS_DN), same(registeredListener));
+ }
+
+ @Test
+ public void testDeregisterAddListenerWithInstantiableRelationDelayed() throws Exception {
+ // arrange
+ ConfigurationRepository configRepository = createConfigRepositoryWithDNs(ROOT_CONFIG_DN);
+ ServerManagementContext context = new ServerManagementContext(configRepository);
+ ServerManagedObject<RootCfg> root = context.getRootConfigurationManagedObject();
+
+ ConfigurationAddListener<TestParentCfg> parentListener = mock(ConfigurationAddListener.class);
+ ConfigAddListener registeredListener =
+ registerAddListenerForTestParentDelayed(configRepository, root, parentListener);
+ when(configRepository.getAddListeners(ROOT_CONFIG_DN)).thenReturn(Arrays.asList(registeredListener));
+
+ // act
+ root.deregisterAddListener(TestCfg.getTestOneToManyParentRelationDefinition(), parentListener);
+
+ // assert
+ verify(configRepository).deregisterAddListener(eq(ROOT_CONFIG_DN), same(registeredListener));
+ }
+
+}
\ No newline at end of file
diff --git a/opendj-sdk/opendj-admin/src/test/java/org/opends/server/admin/server/MockConstraint.java b/opendj-sdk/opendj-admin/src/test/java/org/opends/server/admin/server/MockConstraint.java
new file mode 100644
index 0000000..e04476c
--- /dev/null
+++ b/opendj-sdk/opendj-admin/src/test/java/org/opends/server/admin/server/MockConstraint.java
@@ -0,0 +1,146 @@
+/*
+ * 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 legal-notices/CDDLv1_0.txt
+ * or http://forgerock.org/license/CDDLv1.0.html.
+ * 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 legal-notices/CDDLv1_0.txt.
+ * 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
+ *
+ *
+ * Copyright 2008 Sun Microsystems, Inc.
+ */
+package org.opends.server.admin.server;
+
+import java.util.Collection;
+import java.util.Collections;
+
+import org.forgerock.i18n.LocalizableMessage;
+import org.forgerock.opendj.ldap.DN;
+import org.opends.server.admin.Constraint;
+import org.opends.server.admin.client.ClientConstraintHandler;
+import org.opends.server.config.ConfigException;
+import org.opends.server.config.ConfigurationRepository;
+import org.testng.Assert;
+
+/**
+ * A mock constraint which can be configured to refuse various types of
+ * operation.
+ */
+public final class MockConstraint extends Constraint {
+
+ /**
+ * Mock server constraint handler.
+ */
+ private class Handler extends ServerConstraintHandler {
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isDeleteAllowed(ServerManagedObject<?> managedObject,
+ Collection<LocalizableMessage> unacceptableReasons) throws ConfigException {
+ if (!isDeleteAllowed) {
+ unacceptableReasons.add(LocalizableMessage.raw("Configuration cannot be deleted."));
+ }
+
+ return isDeleteAllowed;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isUsable(ServerManagedObject<?> managedObject,
+ Collection<LocalizableMessage> unacceptableReasons) throws ConfigException {
+ if (!isUsable) {
+ unacceptableReasons.add(LocalizableMessage.raw("Configuration is not usable."));
+ }
+
+ return isUsable;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void performPostAdd(ServerManagedObject<?> managedObject) throws ConfigException {
+ // Make sure that the associated config entry exists.
+ DN targetDN = managedObject.getDN();
+ Assert.assertTrue(configRepository.hasEntry(targetDN));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void performPostDelete(ServerManagedObject<?> managedObject) throws ConfigException {
+ // Make sure that the associated config entry does not exist.
+ DN targetDN = managedObject.getDN();
+ Assert.assertTrue(configRepository.hasEntry(targetDN));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void performPostModify(ServerManagedObject<?> managedObject) throws ConfigException {
+ // Make sure that the associated config entry exists.
+ DN targetDN = managedObject.getDN();
+ Assert.assertTrue(configRepository.hasEntry(targetDN));
+ }
+
+ }
+
+ // Determines if delete operations are allowed.
+ private final boolean isDeleteAllowed;
+
+ // Determines if configurations can be decoded.
+ private final boolean isUsable;
+
+ private final ConfigurationRepository configRepository;
+
+ /**
+ * Creates a new mock constraint.
+ *
+ * @param isUsable
+ * Determines if configurations can be decoded.
+ * @param isDeleteAllowed
+ * Determines if delete operations are allowed.
+ * @param configRepository
+ * Configuration entries.
+ */
+ public MockConstraint(boolean isUsable, boolean isDeleteAllowed, ConfigurationRepository configRepository) {
+ this.isUsable = isUsable;
+ this.isDeleteAllowed = isDeleteAllowed;
+ this.configRepository = configRepository;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Collection<ClientConstraintHandler> getClientConstraintHandlers() {
+ return Collections.emptySet();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Collection<ServerConstraintHandler> getServerConstraintHandlers() {
+ return Collections.<ServerConstraintHandler> singleton(new Handler());
+ }
+
+}
--
Gitblit v1.10.0