From 57a045a15fcb098b295f8acee77239bd12c76fb1 Mon Sep 17 00:00:00 2001
From: matthew_swift <matthew_swift@localhost>
Date: Wed, 05 Sep 2007 22:57:40 +0000
Subject: [PATCH] Improvements to the server-side constraint violation APIs. Now there are just two server-side constraint enforcement call-backs: isUsable and isDeleteAllowed. The first is invoked whenever a managed object is decoded (except in the case where it's about to be deleted). The second is invoked whenever a managed object is about to be deleted. With this change we will now detect constraint violations during server initialization, not just when config change/add/delete events occur.
---
opendj-sdk/opends/src/server/org/opends/server/admin/server/ConfigAddListenerAdaptor.java | 31 --
opendj-sdk/opends/src/server/org/opends/server/admin/server/ConfigExceptionFactory.java | 26 ++
opendj-sdk/opends/src/server/org/opends/server/admin/server/ConfigChangeListenerAdaptor.java | 42 --
opendj-sdk/opends/src/server/org/opends/server/admin/server/ConfigDeleteListenerAdaptor.java | 12
opendj-sdk/opends/src/server/org/opends/server/admin/server/ServerManagedObject.java | 58 +++++
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/ConstraintTest.java | 90 +++++++-
opendj-sdk/opends/src/server/org/opends/server/admin/server/AbstractConfigListenerAdaptor.java | 4
opendj-sdk/opends/src/messages/messages/admin.properties | 4
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/MockConstraint.java | 65 ++---
opendj-sdk/opends/src/server/org/opends/server/admin/server/ConstraintViolationException.java | 179 ++++++++++++++++
opendj-sdk/opends/src/server/org/opends/server/admin/server/ServerConstraintHandler.java | 94 +++----
opendj-sdk/opends/src/server/org/opends/server/admin/server/ServerManagementContext.java | 11
12 files changed, 438 insertions(+), 178 deletions(-)
diff --git a/opendj-sdk/opends/src/messages/messages/admin.properties b/opendj-sdk/opends/src/messages/messages/admin.properties
index c9645c0..af43615 100644
--- a/opendj-sdk/opends/src/messages/messages/admin.properties
+++ b/opendj-sdk/opends/src/messages/messages/admin.properties
@@ -255,3 +255,7 @@
recognized
SEVERE_ERR_COMMUNICATION_EXCEPTION_DEFAULT_CAUSE_111=A communication problem \
occurred while contacting the server: %s
+SEVERE_ERR_CONSTRAINT_VIOLATION_EXCEPTION_SINGLE_112=The following \
+ constraint violation occurred: %s
+SEVERE_ERR_CONSTRAINT_VIOLATION_EXCEPTION_PLURAL_113=The following \
+ constraint violations occurred: %s
diff --git a/opendj-sdk/opends/src/server/org/opends/server/admin/server/AbstractConfigListenerAdaptor.java b/opendj-sdk/opends/src/server/org/opends/server/admin/server/AbstractConfigListenerAdaptor.java
index c70daa6..7938f6a 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/admin/server/AbstractConfigListenerAdaptor.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/admin/server/AbstractConfigListenerAdaptor.java
@@ -28,7 +28,7 @@
-import java.util.List;
+import java.util.Collection;
import org.opends.messages.Message;
import org.opends.messages.MessageBuilder;
@@ -57,7 +57,7 @@
* @param unacceptableReason
* The single message to which messages should be appended.
*/
- protected final void generateUnacceptableReason(List<Message> reasons,
+ protected final void generateUnacceptableReason(Collection<Message> reasons,
MessageBuilder unacceptableReason) {
boolean isFirst = true;
for (Message reason : reasons) {
diff --git a/opendj-sdk/opends/src/server/org/opends/server/admin/server/ConfigAddListenerAdaptor.java b/opendj-sdk/opends/src/server/org/opends/server/admin/server/ConfigAddListenerAdaptor.java
index 33017e5..ec306cb 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/admin/server/ConfigAddListenerAdaptor.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/admin/server/ConfigAddListenerAdaptor.java
@@ -28,7 +28,6 @@
-import static org.opends.messages.AdminMessages.*;
import static org.opends.server.loggers.debug.DebugLogger.*;
import java.util.LinkedList;
@@ -168,7 +167,7 @@
for (ServerConstraintHandler handler : constraint
.getServerConstraintHandlers()) {
try {
- handler.performAddPostCondition(cachedManagedObject);
+ handler.performPostAdd(cachedManagedObject);
} catch (ConfigException e) {
if (debugEnabled()) {
TRACER.debugCaught(DebugLogLevel.ERROR, e);
@@ -216,35 +215,17 @@
}
cachedConfiguration = cachedManagedObject.getConfiguration();
- List<Message> reasons = new LinkedList<Message>();
-
- // Enforce any constraints.
- boolean isAcceptable = true;
- ManagedObjectDefinition<?, ?> d = cachedManagedObject
- .getManagedObjectDefinition();
- for (Constraint constraint : d.getAllConstraints()) {
- for (ServerConstraintHandler handler : constraint
- .getServerConstraintHandlers()) {
- try {
- if (!handler.isAddAcceptable(cachedManagedObject, reasons)) {
- isAcceptable = false;
- }
- } catch (ConfigException e) {
- Message message = ERR_SERVER_CONSTRAINT_EXCEPTION.get(e
- .getMessageObject());
- reasons.add(message);
- isAcceptable = false;
- }
- }
- }
// Give up immediately if a constraint violation occurs.
- if (!isAcceptable) {
- generateUnacceptableReason(reasons, unacceptableReason);
+ try {
+ cachedManagedObject.ensureIsUsable();
+ } catch (ConstraintViolationException e) {
+ generateUnacceptableReason(e.getMessages(), unacceptableReason);
return false;
}
// Let the add listener decide.
+ List<Message> reasons = new LinkedList<Message>();
if (listener.isConfigurationAddAcceptable(cachedConfiguration, reasons)) {
return true;
} else {
diff --git a/opendj-sdk/opends/src/server/org/opends/server/admin/server/ConfigChangeListenerAdaptor.java b/opendj-sdk/opends/src/server/org/opends/server/admin/server/ConfigChangeListenerAdaptor.java
index 0cc4e9f..c4e4848 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/admin/server/ConfigChangeListenerAdaptor.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/admin/server/ConfigChangeListenerAdaptor.java
@@ -28,9 +28,6 @@
-import org.opends.messages.Message;
-
-import static org.opends.messages.AdminMessages.*;
import static org.opends.server.loggers.debug.DebugLogger.*;
import java.util.Collection;
@@ -39,6 +36,9 @@
import java.util.List;
import java.util.Set;
+import org.opends.messages.AdminMessages;
+import org.opends.messages.Message;
+import org.opends.messages.MessageBuilder;
import org.opends.server.admin.AbsoluteInheritedDefaultBehaviorProvider;
import org.opends.server.admin.AbstractManagedObjectDefinition;
import org.opends.server.admin.AliasDefaultBehaviorProvider;
@@ -57,11 +57,8 @@
import org.opends.server.config.ConfigEntry;
import org.opends.server.config.ConfigException;
import org.opends.server.core.DirectoryServer;
-import org.opends.server.loggers.debug.DebugTracer;
import org.opends.server.loggers.ErrorLogger;
-import org.opends.messages.AdminMessages;
-
-import org.opends.messages.MessageBuilder;
+import org.opends.server.loggers.debug.DebugTracer;
import org.opends.server.types.ConfigChangeResult;
import org.opends.server.types.DN;
import org.opends.server.types.DebugLogLevel;
@@ -322,7 +319,7 @@
for (ServerConstraintHandler handler : constraint
.getServerConstraintHandlers()) {
try {
- handler.performModifyPostCondition(cachedManagedObject);
+ handler.performPostModify(cachedManagedObject);
} catch (ConfigException e) {
if (debugEnabled()) {
TRACER.debugCaught(DebugLogLevel.ERROR, e);
@@ -377,35 +374,16 @@
return false;
}
- List<Message> reasons = new LinkedList<Message>();
-
- // Enforce any constraints.
- boolean isAcceptable = true;
- ManagedObjectDefinition<?, ?> d = cachedManagedObject
- .getManagedObjectDefinition();
- for (Constraint constraint : d.getAllConstraints()) {
- for (ServerConstraintHandler handler : constraint
- .getServerConstraintHandlers()) {
- try {
- if (!handler.isModifyAcceptable(cachedManagedObject, reasons)) {
- isAcceptable = false;
- }
- } catch (ConfigException e) {
- Message message = ERR_SERVER_CONSTRAINT_EXCEPTION.get(e
- .getMessageObject());
- reasons.add(message);
- isAcceptable = false;
- }
- }
- }
-
// Give up immediately if a constraint violation occurs.
- if (!isAcceptable) {
- generateUnacceptableReason(reasons, unacceptableReason);
+ try {
+ cachedManagedObject.ensureIsUsable();
+ } catch (ConstraintViolationException e) {
+ generateUnacceptableReason(e.getMessages(), unacceptableReason);
return false;
}
// Let the change listener decide.
+ List<Message> reasons = new LinkedList<Message>();
if (listener.isConfigurationChangeAcceptable(cachedManagedObject
.getConfiguration(), reasons)) {
return true;
diff --git a/opendj-sdk/opends/src/server/org/opends/server/admin/server/ConfigDeleteListenerAdaptor.java b/opendj-sdk/opends/src/server/org/opends/server/admin/server/ConfigDeleteListenerAdaptor.java
index 443a278..1a3ac54 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/admin/server/ConfigDeleteListenerAdaptor.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/admin/server/ConfigDeleteListenerAdaptor.java
@@ -169,7 +169,7 @@
for (ServerConstraintHandler handler : constraint
.getServerConstraintHandlers()) {
try {
- handler.performDeletePostCondition(cachedManagedObject);
+ handler.performPostDelete(cachedManagedObject);
} catch (ConfigException e) {
if (debugEnabled()) {
TRACER.debugCaught(DebugLogLevel.ERROR, e);
@@ -220,27 +220,27 @@
List<Message> reasons = new LinkedList<Message>();
// Enforce any constraints.
- boolean isAcceptable = true;
+ boolean isDeleteAllowed = true;
ManagedObjectDefinition<?, ?> d = cachedManagedObject
.getManagedObjectDefinition();
for (Constraint constraint : d.getAllConstraints()) {
for (ServerConstraintHandler handler : constraint
.getServerConstraintHandlers()) {
try {
- if (!handler.isDeleteAcceptable(cachedManagedObject, reasons)) {
- isAcceptable = false;
+ if (!handler.isDeleteAllowed(cachedManagedObject, reasons)) {
+ isDeleteAllowed = false;
}
} catch (ConfigException e) {
Message message = ERR_SERVER_CONSTRAINT_EXCEPTION.get(e
.getMessageObject());
reasons.add(message);
- isAcceptable = false;
+ isDeleteAllowed = false;
}
}
}
// Give up immediately if a constraint violation occurs.
- if (!isAcceptable) {
+ if (!isDeleteAllowed) {
generateUnacceptableReason(reasons, unacceptableReason);
return false;
}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/admin/server/ConfigExceptionFactory.java b/opendj-sdk/opends/src/server/org/opends/server/admin/server/ConfigExceptionFactory.java
index 4faf5d7..b319a74 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/admin/server/ConfigExceptionFactory.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/admin/server/ConfigExceptionFactory.java
@@ -96,7 +96,6 @@
public ConfigException createDecodingExceptionAdaptor(
ServerManagedObjectDecodingException e) {
-
DN dn = e.getPartialManagedObject().getDN();
Message message =
AdminMessages.ERR_ADMIN_MANAGED_OBJECT_DECODING_PROBLEM.get(
@@ -108,13 +107,32 @@
/**
- * Create an exception that describes a problem that occurred when attempting
- * to load and instantiate a class.
+ * Create a configuration exception from a constraints violation
+ * decoding exception.
+ *
+ * @param e
+ * The constraints violation decoding exception.
+ * @return Returns the configuration exception.
+ */
+ public ConfigException createDecodingExceptionAdaptor(
+ ConstraintViolationException e) {
+ DN dn = e.getManagedObject().getDN();
+ Message message = AdminMessages.ERR_ADMIN_MANAGED_OBJECT_DECODING_PROBLEM
+ .get(String.valueOf(dn), stackTraceToSingleLineString(e));
+ return new ConfigException(message, e);
+ }
+
+
+
+ /**
+ * Create an exception that describes a problem that occurred when
+ * attempting to load and instantiate a class.
*
* @param dn
* The dn of the configuration entry was being processed.
* @param className
- * The name of the class that could not be loaded or instantiated.
+ * The name of the class that could not be loaded or
+ * instantiated.
* @param e
* The exception that occurred.
* @return Returns the configuration exception.
diff --git a/opendj-sdk/opends/src/server/org/opends/server/admin/server/ConstraintViolationException.java b/opendj-sdk/opends/src/server/org/opends/server/admin/server/ConstraintViolationException.java
new file mode 100644
index 0000000..32d98c5
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/admin/server/ConstraintViolationException.java
@@ -0,0 +1,179 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ * Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ * Portions Copyright 2007 Sun Microsystems, Inc.
+ */
+
+package org.opends.server.admin.server;
+
+
+
+import static org.opends.messages.AdminMessages.*;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+
+import org.opends.messages.Message;
+import org.opends.messages.MessageBuilder;
+import org.opends.server.admin.DecodingException;
+import org.opends.server.util.Validator;
+
+
+
+/**
+ * This exception is thrown when the server refuses to use or delete a
+ * managed object due to one or more constraints that cannot be
+ * satisfied.
+ */
+public class ConstraintViolationException extends DecodingException {
+
+ /**
+ * Serialization ID.
+ */
+ private static final long serialVersionUID = -4902443848460011875L;
+
+ // The server managed object.
+ private final ServerManagedObject<?> managedObject;
+
+
+
+ // Gets the default message.
+ private static Message getDefaultMessage(Collection<Message> messages) {
+ Validator.ensureNotNull(messages);
+ Validator.ensureTrue(!messages.isEmpty());
+
+ if (messages.size() == 1) {
+ return ERR_CONSTRAINT_VIOLATION_EXCEPTION_SINGLE.get(messages.iterator()
+ .next());
+ } else {
+ return ERR_CONSTRAINT_VIOLATION_EXCEPTION_PLURAL
+ .get(getSingleMessage(messages));
+ }
+ }
+
+
+
+ // Merge the messages into a single message.
+ private static Message getSingleMessage(Collection<Message> messages) {
+ if (messages.size() == 1) {
+ return messages.iterator().next();
+ } else {
+ MessageBuilder builder = new MessageBuilder();
+
+ boolean isFirst = true;
+ for (Message m : messages) {
+ if (!isFirst) {
+ builder.append("; ");
+ }
+ builder.append(m);
+ isFirst = false;
+ }
+
+ return builder.toMessage();
+ }
+ }
+
+ // The messages describing the constraint violations that occurred.
+ private final Collection<Message> messages;
+
+
+
+ /**
+ * Creates a new constraint violation exception with the provided
+ * messages.
+ *
+ * @param managedObject
+ * The server managed object which caused the constraint
+ * violations.
+ * @param messages
+ * The messages describing the constraint violations that
+ * occurred (must be non-<code>null</code> and
+ * non-empty).
+ */
+ public ConstraintViolationException(ServerManagedObject<?> managedObject,
+ Collection<Message> messages) {
+ super(getDefaultMessage(messages));
+
+ this.managedObject = managedObject;
+ this.messages = new ArrayList<Message>(messages);
+ }
+
+
+
+ /**
+ * Creates a new constraint violation exception with the provided
+ * message.
+ *
+ * @param managedObject
+ * The server managed object which caused the constraint
+ * violations.
+ * @param message
+ * The message describing the constraint violation that
+ * occurred.
+ */
+ public ConstraintViolationException(ServerManagedObject<?> managedObject,
+ Message message) {
+ this(managedObject, Collections.singleton(message));
+ }
+
+
+
+ /**
+ * Gets an unmodifiable collection view of the messages describing
+ * the constraint violations that occurred.
+ *
+ * @return Returns an unmodifiable collection view of the messages
+ * describing the constraint violations that occurred.
+ */
+ public Collection<Message> getMessages() {
+ return Collections.unmodifiableCollection(messages);
+ }
+
+
+
+ /**
+ * Creates a single message listing all the messages combined into a
+ * single list separated by semi-colons.
+ *
+ * @return Returns a single message listing all the messages
+ * combined into a single list separated by semi-colons.
+ */
+ public Message getMessagesAsSingleMessage() {
+ return getSingleMessage(messages);
+ }
+
+
+
+ /**
+ * Gets the server managed object which caused the constraint
+ * violations.
+ *
+ * @return Returns the server managed object which caused the
+ * constraint violations.
+ */
+ public ServerManagedObject<?> getManagedObject() {
+ return managedObject;
+ }
+}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/admin/server/ServerConstraintHandler.java b/opendj-sdk/opends/src/server/org/opends/server/admin/server/ServerConstraintHandler.java
index 652d8f8..430fc17 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/admin/server/ServerConstraintHandler.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/admin/server/ServerConstraintHandler.java
@@ -67,42 +67,14 @@
/**
- * Determines whether or not the newly created managed object which
- * is about to be added to the server configuration satisfies this
- * constraint.
+ * Determines whether or not the existing managed object can be
+ * deleted from the server's configuration. For example, an
+ * implementation might enforce referential integrity by preventing
+ * referenced managed objects from being deleted.
* <p>
* If the constraint is not satisfied, the implementation must
* return <code>false</code> and add a message describing why the
- * constraint was not satisfied.
- * <p>
- * The default implementation is to return <code>true</code>.
- *
- * @param managedObject
- * The new managed object.
- * @param unacceptableReasons
- * A list of messages to which error messages should be
- * added.
- * @return Returns <code>true</code> if this constraint is
- * satisfied, or <code>false</code> if it is not.
- * @throws ConfigException
- * If an configuration exception prevented this constraint
- * from being evaluated.
- */
- public boolean isAddAcceptable(ServerManagedObject<?> managedObject,
- Collection<Message> unacceptableReasons) throws ConfigException {
- return true;
- }
-
-
-
- /**
- * Determines whether or not the existing managed object which is
- * about to be deleted from the server configuration satisfies this
- * constraint.
- * <p>
- * If the constraint is not satisfied, the implementation must
- * return <code>false</code> and add a message describing why the
- * constraint was not satisfied.
+ * managed object cannot be deleted.
* <p>
* The default implementation is to return <code>true</code>.
*
@@ -112,12 +84,13 @@
* A list of messages to which error messages should be
* added.
* @return Returns <code>true</code> if this constraint is
- * satisfied, or <code>false</code> if it is not.
+ * satisfied, or <code>false</code> if it is not and the
+ * managed object cannot be deleted.
* @throws ConfigException
* If an configuration exception prevented this constraint
* from being evaluated.
*/
- public boolean isDeleteAcceptable(ServerManagedObject<?> managedObject,
+ public boolean isDeleteAllowed(ServerManagedObject<?> managedObject,
Collection<Message> unacceptableReasons) throws ConfigException {
return true;
}
@@ -125,28 +98,32 @@
/**
- * Determines whether or not the changes to an existing managed
- * object which are about to be committed to the server
- * configuration satisfies this constraint.
+ * Determines whether or not the provided managed object can be used
+ * by the server. This method is invoked each time a managed object
+ * is decoded by the administration framework: when an attempt is
+ * made to add a new configuration, modify an existing
+ * configuration, or during server initialization. If the constraint
+ * is not satisfied the managed object will be rejected.
* <p>
* If the constraint is not satisfied, the implementation must
* return <code>false</code> and add a message describing why the
- * constraint was not satisfied.
+ * managed object is not usable.
* <p>
* The default implementation is to return <code>true</code>.
*
* @param managedObject
- * The modified managed object.
+ * The new managed object.
* @param unacceptableReasons
* A list of messages to which error messages should be
* added.
- * @return Returns <code>true</code> if this modify is satisfied,
- * or <code>false</code> if it is not.
+ * @return Returns <code>true</code> if this constraint is
+ * satisfied, or <code>false</code> if it is not and the
+ * managed object cannot be used.
* @throws ConfigException
* If an configuration exception prevented this constraint
* from being evaluated.
*/
- public boolean isModifyAcceptable(ServerManagedObject<?> managedObject,
+ public boolean isUsable(ServerManagedObject<?> managedObject,
Collection<Message> unacceptableReasons) throws ConfigException {
return true;
}
@@ -154,17 +131,22 @@
/**
- * Perform any add post-condition processing.
+ * Performs any post-add processing required by this constraint.
+ * This method is invoked after a new managed object has been
+ * accepted for use by the administration framework. This might
+ * occur during initialization or when a managed object is added at
+ * run-time.
* <p>
* The default implementation is to do nothing.
*
* @param managedObject
- * The managed object which was added.
+ * The managed object which has just been added to the
+ * server's configuration.
* @throws ConfigException
- * If the post-condition processing fails due to a
- * configuration exception.
+ * If the post-add processing fails due to a configuration
+ * exception.
*/
- public void performAddPostCondition(ServerManagedObject<?> managedObject)
+ public void performPostAdd(ServerManagedObject<?> managedObject)
throws ConfigException {
// Do nothing.
}
@@ -172,17 +154,19 @@
/**
- * Perform any delete post-condition processing.
+ * Performs any post-delete processing required by this constraint.
+ * This method is invoked after a managed object has been accepted
+ * for deletion from the server's configuration.
* <p>
* The default implementation is to do nothing.
*
* @param managedObject
* The managed object which was deleted.
* @throws ConfigException
- * If the post-condition processing fails due to a
+ * If the post-delete processing fails due to a
* configuration exception.
*/
- public void performDeletePostCondition(ServerManagedObject<?> managedObject)
+ public void performPostDelete(ServerManagedObject<?> managedObject)
throws ConfigException {
// Do nothing.
}
@@ -190,17 +174,19 @@
/**
- * Perform any modify post-condition processing.
+ * Performs any post-modify processing required by this constraint.
+ * This method is invoked after changes to an existing managed
+ * object have been accepted.
* <p>
* The default implementation is to do nothing.
*
* @param managedObject
* The managed object which was modified.
* @throws ConfigException
- * If the post-condition processing fails due to a
+ * If the post-modify processing fails due to a
* configuration exception.
*/
- public void performModifyPostCondition(ServerManagedObject<?> managedObject)
+ public void performPostModify(ServerManagedObject<?> managedObject)
throws ConfigException {
// Do nothing.
}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/admin/server/ServerManagedObject.java b/opendj-sdk/opends/src/server/org/opends/server/admin/server/ServerManagedObject.java
index 0c527d8..c18c976 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/admin/server/ServerManagedObject.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/admin/server/ServerManagedObject.java
@@ -29,9 +29,12 @@
+import static org.opends.messages.AdminMessages.*;
import static org.opends.server.loggers.debug.DebugLogger.*;
import static org.opends.server.util.StaticUtils.*;
+import java.util.LinkedList;
+import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
@@ -40,6 +43,7 @@
import org.opends.messages.AdminMessages;
import org.opends.messages.Message;
import org.opends.server.admin.Configuration;
+import org.opends.server.admin.Constraint;
import org.opends.server.admin.InstantiableRelationDefinition;
import org.opends.server.admin.ManagedObjectDefinition;
import org.opends.server.admin.ManagedObjectPath;
@@ -536,6 +540,25 @@
ConfigChangeListener adaptor = new ConfigChangeListenerAdaptor<S>(path,
listener);
configEntry.registerChangeListener(adaptor);
+
+ // Change listener registration usually signifies that a managed
+ // object has been accepted and added to the server configuration
+ // either during initialization post-add.
+
+ // FIXME: we should prevent multiple invocations in the case where
+ // multiple change listeners are registered for the same object.
+ for (Constraint constraint : definition.getAllConstraints()) {
+ for (ServerConstraintHandler handler : constraint
+ .getServerConstraintHandlers()) {
+ try {
+ handler.performPostAdd(this);
+ } catch (ConfigException e) {
+ if (debugEnabled()) {
+ TRACER.debugCaught(DebugLogLevel.ERROR, e);
+ }
+ }
+ }
+ }
}
@@ -601,6 +624,41 @@
/**
+ * Determines whether or not this managed object can be used by the
+ * server.
+ *
+ * @throws ConstraintViolationException
+ * If one or more constraints determined that this managed
+ * object cannot be used by the server.
+ */
+ void ensureIsUsable() throws ConstraintViolationException {
+ // Enforce any constraints.
+ boolean isUsable = true;
+ List<Message> reasons = new LinkedList<Message>();
+ for (Constraint constraint : definition.getAllConstraints()) {
+ for (ServerConstraintHandler handler : constraint
+ .getServerConstraintHandlers()) {
+ try {
+ if (!handler.isUsable(this, reasons)) {
+ isUsable = false;
+ }
+ } catch (ConfigException e) {
+ Message message = ERR_SERVER_CONSTRAINT_EXCEPTION.get(e
+ .getMessageObject());
+ reasons.add(message);
+ isUsable = false;
+ }
+ }
+ }
+
+ if (!isUsable) {
+ throw new ConstraintViolationException(this, reasons);
+ }
+ }
+
+
+
+ /**
* Update the config entry 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
diff --git a/opendj-sdk/opends/src/server/org/opends/server/admin/server/ServerManagementContext.java b/opendj-sdk/opends/src/server/org/opends/server/admin/server/ServerManagementContext.java
index a8d3391..d663430 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/admin/server/ServerManagementContext.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/admin/server/ServerManagementContext.java
@@ -456,13 +456,22 @@
DN targetDN = DNBuilder.create(path);
ConfigEntry configEntry = getManagedObjectConfigEntry(targetDN);
try {
- return decode(path, configEntry);
+ ServerManagedObject<? extends S> managedObject;
+ managedObject = decode(path, configEntry);
+
+ // Enforce any constraints.
+ managedObject.ensureIsUsable();
+
+ return managedObject;
} catch (DefinitionDecodingException e) {
throw ConfigExceptionFactory.getInstance()
.createDecodingExceptionAdaptor(targetDN, e);
} catch (ServerManagedObjectDecodingException e) {
throw ConfigExceptionFactory.getInstance()
.createDecodingExceptionAdaptor(e);
+ } catch (ConstraintViolationException e) {
+ throw ConfigExceptionFactory.getInstance()
+ .createDecodingExceptionAdaptor(e);
}
}
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/ConstraintTest.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/ConstraintTest.java
index a234ff8..0f2e835 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/ConstraintTest.java
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/ConstraintTest.java
@@ -38,6 +38,7 @@
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.admin.client.ldap.JNDIDirContextAdaptor;
import org.opends.server.admin.std.server.RootCfg;
@@ -60,8 +61,7 @@
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";
+ private static final String TEST_CHILD_1_DN = "cn=test child 1,cn=test children,cn=test parent 1,cn=test parents,cn=config";
@@ -226,6 +226,75 @@
/**
+ * 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
@@ -237,7 +306,7 @@
AddListener listener = new AddListener();
parent.addTestChildAddListener(listener);
- MockConstraint constraint = new MockConstraint(true, false, false);
+ MockConstraint constraint = new MockConstraint(true, false);
TestCfg.addConstraint(constraint);
try {
@@ -271,7 +340,7 @@
AddListener listener = new AddListener();
parent.addTestChildAddListener(listener);
- MockConstraint constraint = new MockConstraint(false, true, true);
+ MockConstraint constraint = new MockConstraint(false, true);
TestCfg.addConstraint(constraint);
try {
@@ -305,7 +374,7 @@
DeleteListener listener = new DeleteListener();
parent.addTestChildDeleteListener(listener);
- MockConstraint constraint = new MockConstraint(false, false, true);
+ MockConstraint constraint = new MockConstraint(false, true);
TestCfg.addConstraint(constraint);
try {
@@ -341,7 +410,7 @@
DeleteListener listener = new DeleteListener();
parent.addTestChildDeleteListener(listener);
- MockConstraint constraint = new MockConstraint(true, true, false);
+ MockConstraint constraint = new MockConstraint(true, false);
TestCfg.addConstraint(constraint);
try {
@@ -381,14 +450,14 @@
public void testChangeConstraintSuccess() throws Exception {
TestParentCfg parent = getParent("test parent 1");
- MockConstraint constraint = new MockConstraint(false, true, false);
- TestCfg.addConstraint(constraint);
+ 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);
@@ -428,15 +497,14 @@
@Test
public void testChangeConstraintFail() throws Exception {
TestParentCfg parent = getParent("test parent 1");
-
- MockConstraint constraint = new MockConstraint(true, false, true);
- TestCfg.addConstraint(constraint);
+ 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);
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/MockConstraint.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/MockConstraint.java
index e5d9368..77c594d 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/MockConstraint.java
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/MockConstraint.java
@@ -57,13 +57,14 @@
* {@inheritDoc}
*/
@Override
- public boolean isAddAcceptable(ServerManagedObject<?> managedObject,
+ public boolean isDeleteAllowed(ServerManagedObject<?> managedObject,
Collection<Message> unacceptableReasons) throws ConfigException {
- if (!allowAdds) {
- unacceptableReasons.add(Message.raw("Adds not allowed"));
+ if (!isDeleteAllowed) {
+ unacceptableReasons
+ .add(Message.raw("Configuration cannot be deleted."));
}
- return allowAdds;
+ return isDeleteAllowed;
}
@@ -72,13 +73,13 @@
* {@inheritDoc}
*/
@Override
- public boolean isDeleteAcceptable(ServerManagedObject<?> managedObject,
+ public boolean isUsable(ServerManagedObject<?> managedObject,
Collection<Message> unacceptableReasons) throws ConfigException {
- if (!allowDeletes) {
- unacceptableReasons.add(Message.raw("Deletes not allowed"));
+ if (!isUsable) {
+ unacceptableReasons.add(Message.raw("Configuration is not usable."));
}
- return allowDeletes;
+ return isUsable;
}
@@ -87,22 +88,7 @@
* {@inheritDoc}
*/
@Override
- public boolean isModifyAcceptable(ServerManagedObject<?> managedObject,
- Collection<Message> unacceptableReasons) throws ConfigException {
- if (!allowModifies) {
- unacceptableReasons.add(Message.raw("Modifies not allowed"));
- }
-
- return allowModifies;
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void performAddPostCondition(ServerManagedObject<?> managedObject)
+ public void performPostAdd(ServerManagedObject<?> managedObject)
throws ConfigException {
// Make sure that the associated config entry exists.
DN targetDN = managedObject.getDN();
@@ -116,7 +102,7 @@
* {@inheritDoc}
*/
@Override
- public void performDeletePostCondition(ServerManagedObject<?> managedObject)
+ public void performPostDelete(ServerManagedObject<?> managedObject)
throws ConfigException {
// Make sure that the associated config entry does not exist.
DN targetDN = managedObject.getDN();
@@ -130,7 +116,7 @@
* {@inheritDoc}
*/
@Override
- public void performModifyPostCondition(ServerManagedObject<?> managedObject)
+ public void performPostModify(ServerManagedObject<?> managedObject)
throws ConfigException {
// Make sure that the associated config entry exists.
DN targetDN = managedObject.getDN();
@@ -140,32 +126,25 @@
}
- // Determines if add operations are allowed.
- private final boolean allowAdds;
-
- // Determines if modify operations are allowed.
- private final boolean allowModifies;
-
// Determines if delete operations are allowed.
- private final boolean allowDeletes;
+ private final boolean isDeleteAllowed;
+
+ // Determines if configurations can be decoded.
+ private final boolean isUsable;
/**
* Creates a new mock constraint.
*
- * @param allowAdds
- * Determines if add operations are allowed.
- * @param allowModifies
- * Determines if modify operations are allowed.
- * @param allowDeletes
+ * @param isUsable
+ * Determines if configurations can be decoded.
+ * @param isDeleteAllowed
* Determines if delete operations are allowed.
*/
- public MockConstraint(boolean allowAdds, boolean allowModifies,
- boolean allowDeletes) {
- this.allowAdds = allowAdds;
- this.allowModifies = allowModifies;
- this.allowDeletes = allowDeletes;
+ public MockConstraint(boolean isUsable, boolean isDeleteAllowed) {
+ this.isUsable = isUsable;
+ this.isDeleteAllowed = isDeleteAllowed;
}
--
Gitblit v1.10.0