From 8228fb82f3ad657adf7832eb05c624bf48c4a30e Mon Sep 17 00:00:00 2001
From: matthew_swift <matthew_swift@localhost>
Date: Wed, 19 Sep 2007 00:31:06 +0000
Subject: [PATCH] More changes relating to issue 1449: aggregation support.

---
 opends/src/server/org/opends/server/admin/client/MissingMandatoryPropertiesException.java |   46 ++
 opends/src/server/org/opends/server/tools/dsconfig/ArgumentExceptionFactory.java          |  178 +++++++-
 opends/src/server/org/opends/server/admin/client/spi/Driver.java                          |    4 
 opends/src/server/org/opends/server/tools/dsconfig/SetPropSubCommandHandler.java          |  385 ++++++++++++++----
 opends/src/messages/messages/dsconfig.properties                                          |   17 
 opends/src/server/org/opends/server/admin/client/ldap/LDAPManagedObject.java              |   30 
 opends/src/server/org/opends/server/tools/dsconfig/CreateSubCommandHandler.java           |  380 ++++++++++++++----
 opends/src/server/org/opends/server/admin/client/OperationRejectedException.java          |   81 +++
 opends/src/server/org/opends/server/admin/client/spi/AbstractManagedObject.java           |   12 
 opends/src/server/org/opends/server/tools/dsconfig/DSConfig.java                          |   51 -
 opends/src/server/org/opends/server/admin/client/ldap/LDAPDriver.java                     |    9 
 11 files changed, 920 insertions(+), 273 deletions(-)

diff --git a/opends/src/messages/messages/dsconfig.properties b/opends/src/messages/messages/dsconfig.properties
index af4f613..b6055d3 100644
--- a/opends/src/messages/messages/dsconfig.properties
+++ b/opends/src/messages/messages/dsconfig.properties
@@ -101,7 +101,7 @@
  retrieved because another client is currently making conflicting \
  configuration changes
 SEVERE_ERR_DSCFG_ERROR_CREATE_MMPE_1032=The %s could not be created because \
- the following mandatory properties must be defined: %s
+ the following mandatory properties must be defined:
 SEVERE_ERR_DSCFG_ERROR_CREATE_MOAEE_1033=The %s could not be created because \
  there is already an existing one with the same name
 SEVERE_ERR_DSCFG_ERROR_CREATE_AUTHZ_1034=The %s could not be created because \
@@ -424,3 +424,18 @@
 INFO_EDITOR_PROMPT_SELECT_COMPONENTS_REMOVE_132=Select the %s you wish to remove:
 INFO_EDITOR_OPTION_CHANGE_TO_DEFAULT_COMPONENT_133=Change it to the default %s: %s
 INFO_EDITOR_OPTION_CHANGE_TO_COMPONENT_134=Change it to the %s: %s
+INFO_EDITOR_PROMPT_ENABLED_REFERENCED_COMPONENT_135=The referenced %s \
+ called "%s" must be enabled so that it can be used with this %s. Do \
+ you want to enabled it?
+SEVERE_ERR_SET_REFERENCED_COMPONENT_DISABLED_136=The modifications to \
+ the %s cannot be made because it contains a reference to a \
+ disabled %s
+SEVERE_ERR_CREATE_REFERENCED_COMPONENT_DISABLED_137=The %s cannot be created \
+ because it contains a reference to a disabled %s
+SEVERE_ERR_CREATE_HEADING_MMPE_SINGLE_138=The %s could not be created because the following mandatory property was not defined:
+SEVERE_ERR_CREATE_HEADING_MMPE_PLURAL_139=The %s could not be created because the following mandatory properties were not defined:
+SEVERE_ERR_MODIFY_HEADING_MMPE_SINGLE_140=The %s could not be modified because the following mandatory property was not defined:
+SEVERE_ERR_MODIFY_HEADING_MMPE_PLURAL_141=The %s could not be modified because the following mandatory properties were not defined:
+INFO_DSCFG_PROMPT_EDIT_142=Would you like to edit the properties of the %s in order to resolve this problem?
+SEVERE_ERR_GET_HEADING_MODE_SINGLE_143=The %s could not be decoded due to the following reason:
+SEVERE_ERR_GET_HEADING_MODE_PLURAL_144=The %s could not be decoded due to the following reasons:
diff --git a/opends/src/server/org/opends/server/admin/client/MissingMandatoryPropertiesException.java b/opends/src/server/org/opends/server/admin/client/MissingMandatoryPropertiesException.java
index 288630e..684b32c 100644
--- a/opends/src/server/org/opends/server/admin/client/MissingMandatoryPropertiesException.java
+++ b/opends/src/server/org/opends/server/admin/client/MissingMandatoryPropertiesException.java
@@ -86,21 +86,37 @@
   // The causes of this exception.
   private final Collection<PropertyIsMandatoryException> causes;
 
+  // Indicates whether the exception occurred during managed object
+  // creation.
+  private final boolean isCreate;
+
+  // The user friendly name of the component that caused this
+  // exception.
+  private final Message ufn;
+
 
 
   /**
    * Creates a new missing mandatory properties exception with the
    * provided causes.
    *
+   * @param ufn
+   *          The user friendly name of the component that caused this
+   *          exception.
    * @param causes
    *          The causes of this exception (must be non-<code>null</code>
    *          and non-empty).
+   * @param isCreate
+   *          Indicates whether the exception occurred during managed
+   *          object creation.
    */
-  public MissingMandatoryPropertiesException(
-      Collection<PropertyIsMandatoryException> causes) {
+  public MissingMandatoryPropertiesException(Message ufn,
+      Collection<PropertyIsMandatoryException> causes, boolean isCreate) {
     super(createMessage(causes));
 
     this.causes = new ArrayList<PropertyIsMandatoryException>(causes);
+    this.ufn = ufn;
+    this.isCreate = isCreate;
   }
 
 
@@ -128,4 +144,30 @@
     return Collections.unmodifiableCollection(causes);
   }
 
+
+
+  /**
+   * Gets the user friendly name of the component that caused this
+   * exception.
+   *
+   * @return Returns the user friendly name of the component that
+   *         caused this exception.
+   */
+  public Message getUserFriendlyName() {
+    return ufn;
+  }
+
+
+
+  /**
+   * Indicates whether or not this exception was thrown during managed
+   * object creation or during modification.
+   *
+   * @return Returns <code>true</code> if this exception was thrown
+   *         during managed object creation.
+   */
+  public boolean isCreate() {
+    return isCreate;
+  }
+
 }
diff --git a/opends/src/server/org/opends/server/admin/client/OperationRejectedException.java b/opends/src/server/org/opends/server/admin/client/OperationRejectedException.java
index fd5ed40..3fc6b22 100644
--- a/opends/src/server/org/opends/server/admin/client/OperationRejectedException.java
+++ b/opends/src/server/org/opends/server/admin/client/OperationRejectedException.java
@@ -57,6 +57,26 @@
 public class OperationRejectedException extends AdminClientException {
 
   /**
+   * The type of operation that caused this exception.
+   */
+  public enum OperationType {
+    /**
+     * A managed object could not be created.
+     */
+    CREATE,
+
+    /**
+     * A managed object could not be deleted.
+     */
+    DELETE,
+
+    /**
+     * A managed object could not be modified.
+     */
+    MODIFY;
+  }
+
+  /**
    * Serialization ID.
    */
   private static final long serialVersionUID = 8547688890613079044L;
@@ -102,14 +122,27 @@
   // The messages describing the constraint violations that occurred.
   private final Collection<Message> messages;
 
+  // The type of operation that caused this exception.
+  private final OperationType type;
+
+  // The user friendly name of the component that caused this
+  // exception.
+  private final Message ufn;
+
 
 
   /**
    * Creates a new operation rejected exception with a default
    * message.
+   *
+   * @param type
+   *          The type of operation that caused this exception.
+   * @param ufn
+   *          The user friendly name of the component that caused this
+   *          exception.
    */
-  public OperationRejectedException() {
-    this(ERR_OPERATION_REJECTED_DEFAULT.get());
+  public OperationRejectedException(OperationType type, Message ufn) {
+    this(type, ufn, ERR_OPERATION_REJECTED_DEFAULT.get());
   }
 
 
@@ -118,15 +151,23 @@
    * Creates a new operation rejected exception with the provided
    * messages.
    *
+   * @param type
+   *          The type of operation that caused this exception.
+   * @param ufn
+   *          The user friendly name of the component that caused this
+   *          exception.
    * @param messages
    *          The messages describing the constraint violations that
    *          occurred (must be non-<code>null</code> and
    *          non-empty).
    */
-  public OperationRejectedException(Collection<Message> messages) {
+  public OperationRejectedException(OperationType type, Message ufn,
+      Collection<Message> messages) {
     super(getDefaultMessage(messages));
 
     this.messages = new ArrayList<Message>(messages);
+    this.type = type;
+    this.ufn = ufn;
   }
 
 
@@ -135,12 +176,18 @@
    * Creates a new operation rejected exception with the provided
    * message.
    *
+   * @param type
+   *          The type of operation that caused this exception.
+   * @param ufn
+   *          The user friendly name of the component that caused this
+   *          exception.
    * @param message
    *          The message describing the constraint violation that
    *          occurred.
    */
-  public OperationRejectedException(Message message) {
-    this(Collections.singleton(message));
+  public OperationRejectedException(OperationType type, Message ufn,
+      Message message) {
+    this(type, ufn, Collections.singleton(message));
   }
 
 
@@ -169,4 +216,28 @@
     return getSingleMessage(messages);
   }
 
+
+
+  /**
+   * Gets the type of operation that caused this exception.
+   *
+   * @return Returns the type of operation that caused this exception.
+   */
+  public OperationType getOperationType() {
+    return type;
+  }
+
+
+
+  /**
+   * Gets the user friendly name of the component that caused this
+   * exception.
+   *
+   * @return Returns the user friendly name of the component that
+   *         caused this exception.
+   */
+  public Message getUserFriendlyName() {
+    return ufn;
+  }
+
 }
diff --git a/opends/src/server/org/opends/server/admin/client/ldap/LDAPDriver.java b/opends/src/server/org/opends/server/admin/client/ldap/LDAPDriver.java
index 668d495..8b90e8e 100644
--- a/opends/src/server/org/opends/server/admin/client/ldap/LDAPDriver.java
+++ b/opends/src/server/org/opends/server/admin/client/ldap/LDAPDriver.java
@@ -76,6 +76,7 @@
 import org.opends.server.admin.client.ManagedObject;
 import org.opends.server.admin.client.ManagedObjectDecodingException;
 import org.opends.server.admin.client.OperationRejectedException;
+import org.opends.server.admin.client.OperationRejectedException.OperationType;
 import org.opends.server.admin.client.spi.Driver;
 import org.opends.server.admin.client.spi.PropertySet;
 import org.opends.server.admin.std.client.RootCfgClient;
@@ -422,11 +423,15 @@
       connection.deleteSubtree(dn);
     } catch (OperationNotSupportedException e) {
       // Unwilling to perform.
+      AbstractManagedObjectDefinition<?, ?> d =
+        path.getManagedObjectDefinition();
       if (e.getMessage() == null) {
-        throw new OperationRejectedException();
+        throw new OperationRejectedException(OperationType.DELETE, d
+            .getUserFriendlyName());
       } else {
         Message m = Message.raw("%s", e.getMessage());
-        throw new OperationRejectedException(m);
+        throw new OperationRejectedException(OperationType.DELETE, d
+            .getUserFriendlyName(), m);
       }
     } catch (NamingException e) {
       adaptNamingException(e);
diff --git a/opends/src/server/org/opends/server/admin/client/ldap/LDAPManagedObject.java b/opends/src/server/org/opends/server/admin/client/ldap/LDAPManagedObject.java
index ec2f65e..a85c3c4 100644
--- a/opends/src/server/org/opends/server/admin/client/ldap/LDAPManagedObject.java
+++ b/opends/src/server/org/opends/server/admin/client/ldap/LDAPManagedObject.java
@@ -60,6 +60,7 @@
 import org.opends.server.admin.client.ConcurrentModificationException;
 import org.opends.server.admin.client.ManagedObject;
 import org.opends.server.admin.client.OperationRejectedException;
+import org.opends.server.admin.client.OperationRejectedException.OperationType;
 import org.opends.server.admin.client.spi.AbstractManagedObject;
 import org.opends.server.admin.client.spi.Driver;
 import org.opends.server.admin.client.spi.Property;
@@ -160,6 +161,7 @@
       CommunicationException, OperationRejectedException,
       ConcurrentModificationException, ManagedObjectAlreadyExistsException {
     // First make sure that the parent managed object still exists.
+    ManagedObjectDefinition<?, ?> d = getManagedObjectDefinition();
     ManagedObjectPath<?, ?> path = getManagedObjectPath();
     ManagedObjectPath<?, ?> parent = path.parent();
 
@@ -181,8 +183,7 @@
       // TODO: this implementation does not handle relations which
       // comprise of more than one RDN arc (this will probably never
       // be required anyway).
-      LdapName dn = LDAPNameBuilder
-          .create(parent, ir, driver.getLDAPProfile());
+      LdapName dn = LDAPNameBuilder.create(parent, ir, driver.getLDAPProfile());
       if (!driver.entryExists(dn)) {
         // We need to create the entry.
         Attributes attributes = new BasicAttributes();
@@ -205,10 +206,12 @@
         } catch (OperationNotSupportedException e) {
           // Unwilling to perform.
           if (e.getMessage() == null) {
-            throw new OperationRejectedException();
+            throw new OperationRejectedException(OperationType.CREATE, d
+                .getUserFriendlyName());
           } else {
             Message m = Message.raw("%s", e.getMessage());
-            throw new OperationRejectedException(m);
+            throw new OperationRejectedException(OperationType.CREATE, d
+                .getUserFriendlyName(), m);
           }
         } catch (NamingException e) {
           driver.adaptNamingException(e);
@@ -254,10 +257,12 @@
     } catch (OperationNotSupportedException e) {
       // Unwilling to perform.
       if (e.getMessage() == null) {
-        throw new OperationRejectedException();
+        throw new OperationRejectedException(OperationType.CREATE, d
+            .getUserFriendlyName());
       } else {
         Message m = Message.raw("%s", e.getMessage());
-        throw new OperationRejectedException(m);
+        throw new OperationRejectedException(OperationType.CREATE, d
+            .getUserFriendlyName(), m);
       }
     } catch (NamingException e) {
       driver.adaptNamingException(e);
@@ -285,12 +290,11 @@
       AuthorizationException, CommunicationException {
     // Build the list of modified attributes.
     Attributes mods = new BasicAttributes();
-    ManagedObjectDefinition<?, ?> definition = getManagedObjectDefinition();
-    for (PropertyDefinition<?> pd : definition.getAllPropertyDefinitions()) {
+    ManagedObjectDefinition<?, ?> d = getManagedObjectDefinition();
+    for (PropertyDefinition<?> pd : d.getAllPropertyDefinitions()) {
       Property<?> p = getProperty(pd);
       if (p.isModified()) {
-        String attrID = driver.getLDAPProfile().getAttributeName(definition,
-            pd);
+        String attrID = driver.getLDAPProfile().getAttributeName(d, pd);
         Attribute attribute = new BasicAttribute(attrID);
         encodeProperty(attribute, pd);
         mods.put(attribute);
@@ -308,10 +312,12 @@
       } catch (OperationNotSupportedException e) {
         // Unwilling to perform.
         if (e.getMessage() == null) {
-          throw new OperationRejectedException();
+          throw new OperationRejectedException(OperationType.MODIFY, d
+              .getUserFriendlyName());
         } else {
           Message m = Message.raw("%s", e.getMessage());
-          throw new OperationRejectedException(m);
+          throw new OperationRejectedException(OperationType.MODIFY, d
+              .getUserFriendlyName(), m);
         }
       } catch (NamingException e) {
         // Just treat it as a communication problem.
diff --git a/opends/src/server/org/opends/server/admin/client/spi/AbstractManagedObject.java b/opends/src/server/org/opends/server/admin/client/spi/AbstractManagedObject.java
index 88b7ca4..f7fc2a9 100644
--- a/opends/src/server/org/opends/server/admin/client/spi/AbstractManagedObject.java
+++ b/opends/src/server/org/opends/server/admin/client/spi/AbstractManagedObject.java
@@ -68,6 +68,7 @@
 import org.opends.server.admin.client.ManagementContext;
 import org.opends.server.admin.client.MissingMandatoryPropertiesException;
 import org.opends.server.admin.client.OperationRejectedException;
+import org.opends.server.admin.client.OperationRejectedException.OperationType;
 
 
 
@@ -151,7 +152,8 @@
     }
 
     if (!exceptions.isEmpty()) {
-      throw new MissingMandatoryPropertiesException(exceptions);
+      throw new MissingMandatoryPropertiesException(definition
+          .getUserFriendlyName(), exceptions, !existsOnServer);
     }
 
     // Now enforce any constraints.
@@ -175,7 +177,13 @@
     }
 
     if (!isAcceptable) {
-      throw new OperationRejectedException(messages);
+      if (existsOnServer) {
+        throw new OperationRejectedException(OperationType.MODIFY, definition
+            .getUserFriendlyName(), messages);
+      } else {
+        throw new OperationRejectedException(OperationType.CREATE, definition
+            .getUserFriendlyName(), messages);
+      }
     }
 
     // Commit the managed object.
diff --git a/opends/src/server/org/opends/server/admin/client/spi/Driver.java b/opends/src/server/org/opends/server/admin/client/spi/Driver.java
index bc94558..1456a00 100644
--- a/opends/src/server/org/opends/server/admin/client/spi/Driver.java
+++ b/opends/src/server/org/opends/server/admin/client/spi/Driver.java
@@ -69,6 +69,7 @@
 import org.opends.server.admin.client.ManagedObjectDecodingException;
 import org.opends.server.admin.client.ManagementContext;
 import org.opends.server.admin.client.OperationRejectedException;
+import org.opends.server.admin.client.OperationRejectedException.OperationType;
 import org.opends.server.admin.std.client.RootCfgClient;
 
 
@@ -783,7 +784,8 @@
     }
 
     if (!isAcceptable) {
-      throw new OperationRejectedException(messages);
+      throw new OperationRejectedException(OperationType.DELETE, d
+          .getUserFriendlyName(), messages);
     }
 
     deleteManagedObject(path);
diff --git a/opends/src/server/org/opends/server/tools/dsconfig/ArgumentExceptionFactory.java b/opends/src/server/org/opends/server/tools/dsconfig/ArgumentExceptionFactory.java
index 85cc99c..5ed4b82 100644
--- a/opends/src/server/org/opends/server/tools/dsconfig/ArgumentExceptionFactory.java
+++ b/opends/src/server/org/opends/server/tools/dsconfig/ArgumentExceptionFactory.java
@@ -44,10 +44,15 @@
 import org.opends.server.admin.PropertyIsSingleValuedException;
 import org.opends.server.admin.RelationDefinition;
 import org.opends.server.admin.client.IllegalManagedObjectNameException;
+import org.opends.server.admin.client.ManagedObjectDecodingException;
 import org.opends.server.admin.client.MissingMandatoryPropertiesException;
+import org.opends.server.admin.client.OperationRejectedException;
 import org.opends.server.util.args.Argument;
 import org.opends.server.util.args.ArgumentException;
 import org.opends.server.util.cli.CLIException;
+import org.opends.server.util.cli.ConsoleApplication;
+import org.opends.server.util.table.TableBuilder;
+import org.opends.server.util.table.TextTablePrinter;
 
 
 
@@ -103,35 +108,6 @@
 
 
   /**
-   * Creates an argument exception from a missing mandatory properties
-   * exception.
-   *
-   * @param e
-   *          The missing mandatory properties exception.
-   * @param d
-   *          The managed object definition.
-   * @return Returns an argument exception.
-   */
-  public static ArgumentException adaptMissingMandatoryPropertiesException(
-      MissingMandatoryPropertiesException e,
-      AbstractManagedObjectDefinition<?, ?> d) {
-    StringBuilder builder = new StringBuilder();
-    boolean isFirst = true;
-    for (PropertyIsMandatoryException pe : e.getCauses()) {
-      if (!isFirst) {
-        builder.append(", ");
-      }
-      builder.append(pe.getPropertyDefinition().getName());
-      isFirst = false;
-    }
-    Message msg = ERR_DSCFG_ERROR_CREATE_MMPE.get(
-            d.getUserFriendlyName(), builder.toString());
-    return new ArgumentException(msg);
-  }
-
-
-
-  /**
    * Creates an argument exception from a property exception.
    *
    * @param e
@@ -172,6 +148,150 @@
 
 
   /**
+   * Displays a table listing reasons why a managed object could not
+   * be decoded successfully.
+   *
+   * @param app
+   *          The console application.
+   * @param e
+   *          The managed object decoding exception.
+   */
+  public static void displayManagedObjectDecodingException(
+      ConsoleApplication app, ManagedObjectDecodingException e) {
+    AbstractManagedObjectDefinition<?, ?> d = e.getPartialManagedObject()
+        .getManagedObjectDefinition();
+    Message ufn = d.getUserFriendlyName();
+    Message msg;
+    if (e.getCauses().size() == 1) {
+      msg = ERR_GET_HEADING_MODE_SINGLE.get(ufn);
+    } else {
+      msg = ERR_GET_HEADING_MODE_PLURAL.get(ufn);
+    }
+
+    app.println(msg);
+    app.println();
+    TableBuilder builder = new TableBuilder();
+    for (PropertyException pe : e.getCauses()) {
+      ArgumentException ae = adaptPropertyException(pe, d);
+      builder.startRow();
+      builder.appendCell("*");
+      builder.appendCell(ae.getMessage());
+    }
+
+    TextTablePrinter printer = new TextTablePrinter(app.getErrorStream());
+    printer.setDisplayHeadings(false);
+    printer.setColumnWidth(1, 0);
+    printer.setIndentWidth(4);
+    builder.print(printer);
+  }
+
+
+
+  /**
+   * Displays a table listing missing mandatory properties.
+   *
+   * @param app
+   *          The console application.
+   * @param e
+   *          The missing mandatory property exception.
+   */
+  public static void displayMissingMandatoryPropertyException(
+      ConsoleApplication app, MissingMandatoryPropertiesException e) {
+    Message ufn = e.getUserFriendlyName();
+    Message msg;
+    if (e.isCreate()) {
+      if (e.getCauses().size() == 1) {
+        msg = ERR_CREATE_HEADING_MMPE_SINGLE.get(ufn);
+      } else {
+        msg = ERR_CREATE_HEADING_MMPE_PLURAL.get(ufn);
+      }
+    } else {
+      if (e.getCauses().size() == 1) {
+        msg = ERR_MODIFY_HEADING_MMPE_SINGLE.get(ufn);
+      } else {
+        msg = ERR_MODIFY_HEADING_MMPE_PLURAL.get(ufn);
+      }
+    }
+
+    app.println(msg);
+    app.println();
+    TableBuilder builder = new TableBuilder();
+    builder.addSortKey(0);
+    builder.appendHeading(INFO_DSCFG_HEADING_PROPERTY_NAME.get());
+    builder.appendHeading(INFO_DSCFG_HEADING_PROPERTY_SYNTAX.get());
+
+    PropertyDefinitionUsageBuilder b = new PropertyDefinitionUsageBuilder(true);
+    for (PropertyIsMandatoryException pe : e.getCauses()) {
+      PropertyDefinition<?> pd = pe.getPropertyDefinition();
+      builder.startRow();
+      builder.appendCell(pd.getName());
+      builder.appendCell(b.getUsage(pd));
+    }
+
+    TextTablePrinter printer = new TextTablePrinter(app.getErrorStream());
+    printer.setDisplayHeadings(true);
+    printer.setColumnWidth(1, 0);
+    printer.setIndentWidth(4);
+    builder.print(printer);
+  }
+
+
+
+  /**
+   * Displays a table listing the reasons why an operation was
+   * rejected.
+   *
+   * @param app
+   *          The console application.
+   * @param e
+   *          The operation rejected exception.
+   */
+  public static void displayOperationRejectedException(ConsoleApplication app,
+      OperationRejectedException e) {
+    Message ufn = e.getUserFriendlyName();
+    Message msg;
+    switch (e.getOperationType()) {
+    case CREATE:
+      if (e.getMessages().size() == 1) {
+        msg = ERR_DSCFG_ERROR_CREATE_ORE_SINGLE.get(ufn);
+      } else {
+        msg = ERR_DSCFG_ERROR_CREATE_ORE_PLURAL.get(ufn);
+      }
+      break;
+    case DELETE:
+      if (e.getMessages().size() == 1) {
+        msg = ERR_DSCFG_ERROR_DELETE_ORE_SINGLE.get(ufn);
+      } else {
+        msg = ERR_DSCFG_ERROR_DELETE_ORE_PLURAL.get(ufn);
+      }
+      break;
+    default:
+      if (e.getMessages().size() == 1) {
+        msg = ERR_DSCFG_ERROR_MODIFY_ORE_SINGLE.get(ufn);
+      } else {
+        msg = ERR_DSCFG_ERROR_MODIFY_ORE_PLURAL.get(ufn);
+      }
+      break;
+    }
+
+    app.println(msg);
+    app.println();
+    TableBuilder builder = new TableBuilder();
+    for (Message reason : e.getMessages()) {
+      builder.startRow();
+      builder.appendCell("*");
+      builder.appendCell(reason);
+    }
+    TextTablePrinter printer = new TextTablePrinter(app.getErrorStream());
+    printer.setDisplayHeadings(false);
+    printer.setColumnWidth(1, 0);
+    printer.setIndentWidth(4);
+    builder.print(printer);
+  }
+
+
+
+  /**
    * Creates an argument exception which should be used when a
    * property modification argument is incompatible with a previous
    * modification argument.
diff --git a/opends/src/server/org/opends/server/tools/dsconfig/CreateSubCommandHandler.java b/opends/src/server/org/opends/server/tools/dsconfig/CreateSubCommandHandler.java
index 72453b2..21de5a4 100644
--- a/opends/src/server/org/opends/server/tools/dsconfig/CreateSubCommandHandler.java
+++ b/opends/src/server/org/opends/server/tools/dsconfig/CreateSubCommandHandler.java
@@ -29,6 +29,7 @@
 
 
 import static org.opends.messages.DSConfigMessages.*;
+import static org.opends.server.tools.dsconfig.ArgumentExceptionFactory.*;
 
 import java.util.Collection;
 import java.util.Collections;
@@ -44,6 +45,8 @@
 
 import org.opends.messages.Message;
 import org.opends.server.admin.AbstractManagedObjectDefinition;
+import org.opends.server.admin.AggregationPropertyDefinition;
+import org.opends.server.admin.BooleanPropertyDefinition;
 import org.opends.server.admin.Configuration;
 import org.opends.server.admin.ConfigurationClient;
 import org.opends.server.admin.DefaultBehaviorException;
@@ -355,6 +358,285 @@
     return new CreateSubCommandHandler<C, S>(parser, p, r, null, p.child(r));
   }
 
+
+
+  /**
+   * Create the provided managed object.
+   *
+   * @param app
+   *          The console application.
+   * @param context
+   *          The management context.
+   * @param mo
+   *          The managed object to be created.
+   * @return Returns a MenuResult.success() if the managed object was
+   *         created successfully, or MenuResult.quit(), or
+   *         MenuResult.cancel(), if the managed object was edited
+   *         interactively and the user chose to quit or cancel.
+   * @throws ClientException
+   *           If an unrecoverable client exception occurred whilst
+   *           interacting with the server.
+   * @throws CLIException
+   *           If an error occurred whilst interacting with the
+   *           console.
+   */
+  public static MenuResult<Void> createManagedObject(ConsoleApplication app,
+      ManagementContext context, ManagedObject<?> mo) throws ClientException,
+      CLIException {
+    ManagedObjectDefinition<?, ?> d = mo.getManagedObjectDefinition();
+    Message ufn = d.getUserFriendlyName();
+
+    while (true) {
+      // Interactively set properties if applicable.
+      if (app.isInteractive()) {
+        SortedSet<PropertyDefinition<?>> properties =
+          new TreeSet<PropertyDefinition<?>>();
+        for (PropertyDefinition<?> pd : d.getAllPropertyDefinitions()) {
+          if (pd.hasOption(PropertyOption.HIDDEN)) {
+            continue;
+          }
+          if (!app.isAdvancedMode() && pd.hasOption(PropertyOption.ADVANCED)) {
+            continue;
+          }
+          properties.add(pd);
+        }
+
+        PropertyValueEditor editor = new PropertyValueEditor(app, context);
+        MenuResult<Void> result = editor.edit(mo, properties, false);
+
+        // Interactively enable/edit referenced components.
+        if (result.isSuccess()) {
+          result = checkReferences(app, context, mo);
+          if (result.isAgain()) {
+            // Edit again.
+            continue;
+          }
+        }
+
+        if (result.isQuit()) {
+          if (!app.isMenuDrivenMode()) {
+            // User chose to cancel any changes.
+            Message msg = INFO_DSCFG_CONFIRM_CREATE_FAIL.get(ufn);
+            app.printVerboseMessage(msg);
+          }
+          return MenuResult.quit();
+        } else if (result.isCancel()) {
+          return MenuResult.cancel();
+        }
+      }
+
+      try {
+        // Create the managed object.
+        mo.commit();
+
+        // Output success message.
+        app.println();
+        Message msg = INFO_DSCFG_CONFIRM_CREATE_SUCCESS.get(ufn);
+        app.printVerboseMessage(msg);
+
+        return MenuResult.success();
+      } catch (MissingMandatoryPropertiesException e) {
+        if (app.isInteractive()) {
+          // If interactive, give the user the chance to fix the
+          // problems.
+          app.println();
+          displayMissingMandatoryPropertyException(app, e);
+          app.println();
+          if (!app.confirmAction(INFO_DSCFG_PROMPT_EDIT_AGAIN.get(ufn), true)) {
+            return MenuResult.cancel();
+          }
+        } else {
+          throw new ClientException(LDAPResultCode.CONSTRAINT_VIOLATION, e
+              .getMessageObject(), e);
+        }
+      } catch (AuthorizationException e) {
+        Message msg = ERR_DSCFG_ERROR_CREATE_AUTHZ.get(ufn);
+        throw new ClientException(LDAPResultCode.INSUFFICIENT_ACCESS_RIGHTS,
+            msg);
+      } catch (ConcurrentModificationException e) {
+        Message msg = ERR_DSCFG_ERROR_CREATE_CME.get(ufn);
+        throw new ClientException(LDAPResultCode.CONSTRAINT_VIOLATION, msg);
+      } catch (OperationRejectedException e) {
+        if (app.isInteractive()) {
+          // If interactive, give the user the chance to fix the
+          // problems.
+          app.println();
+          displayOperationRejectedException(app, e);
+          app.println();
+          if (!app.confirmAction(INFO_DSCFG_PROMPT_EDIT_AGAIN.get(ufn), true)) {
+            return MenuResult.cancel();
+          }
+        } else {
+          throw new ClientException(LDAPResultCode.CONSTRAINT_VIOLATION, e
+              .getMessageObject(), e);
+        }
+      } catch (CommunicationException e) {
+        Message msg = ERR_DSCFG_ERROR_CREATE_CE.get(ufn, e.getMessage());
+        throw new ClientException(LDAPResultCode.OPERATIONS_ERROR, msg);
+      } catch (ManagedObjectAlreadyExistsException e) {
+        Message msg = ERR_DSCFG_ERROR_CREATE_MOAEE.get(ufn);
+        throw new ClientException(LDAPResultCode.ENTRY_ALREADY_EXISTS, msg);
+      }
+    }
+  }
+
+
+
+  // Check that any referenced components are enabled if
+  // required.
+  private static MenuResult<Void> checkReferences(ConsoleApplication app,
+      ManagementContext context, ManagedObject<?> mo) throws ClientException,
+      CLIException {
+    ManagedObjectDefinition<?, ?> d = mo.getManagedObjectDefinition();
+    Message ufn = d.getUserFriendlyName();
+
+    for (PropertyDefinition<?> pd : d.getAllPropertyDefinitions()) {
+      if (pd instanceof AggregationPropertyDefinition) {
+        AggregationPropertyDefinition<?, ?> apd =
+          (AggregationPropertyDefinition<?, ?>) pd;
+
+        // Skip this aggregation if it doesn't have an enable
+        // property.
+        BooleanPropertyDefinition tpd = apd
+            .getTargetEnabledPropertyDefinition();
+        if (tpd == null) {
+          continue;
+        }
+
+        // Skip this aggregation if this managed object's enable
+        // properties are not all true.
+        boolean needsEnabling = true;
+        for (BooleanPropertyDefinition bpd : apd
+            .getSourceEnabledPropertyDefinitions()) {
+          if (!mo.getPropertyValue(bpd)) {
+            needsEnabling = false;
+            break;
+          }
+        }
+        if (!needsEnabling) {
+          continue;
+        }
+
+        // The referenced component(s) must be enabled.
+        for (String name : mo.getPropertyValues(apd)) {
+          ManagedObjectPath<?, ?> path = apd.getChildPath(name);
+          Message rufn = path.getManagedObjectDefinition()
+              .getUserFriendlyName();
+          ManagedObject<?> ref;
+          try {
+            ref = context.getManagedObject(path);
+          } catch (AuthorizationException e) {
+            Message msg = ERR_DSCFG_ERROR_CREATE_AUTHZ.get(ufn);
+            throw new ClientException(
+                LDAPResultCode.INSUFFICIENT_ACCESS_RIGHTS, msg);
+          } catch (DefinitionDecodingException e) {
+            Message msg = ERR_DSCFG_ERROR_GET_CHILD_DDE.get(rufn, rufn, rufn);
+            throw new ClientException(LDAPResultCode.OPERATIONS_ERROR, msg);
+          } catch (ManagedObjectDecodingException e) {
+            // FIXME: should not abort here. Instead, display the
+            // errors (if verbose) and apply the changes to the
+            // partial managed object.
+            Message msg = ERR_DSCFG_ERROR_GET_CHILD_MODE.get(rufn);
+            throw new ClientException(LDAPResultCode.OPERATIONS_ERROR, msg, e);
+          } catch (CommunicationException e) {
+            Message msg = ERR_DSCFG_ERROR_CREATE_CE.get(ufn, e.getMessage());
+            throw new ClientException(LDAPResultCode.OPERATIONS_ERROR, msg);
+          } catch (ManagedObjectNotFoundException e) {
+            Message msg = ERR_DSCFG_ERROR_GET_CHILD_MONFE.get(rufn);
+            throw new ClientException(LDAPResultCode.NO_SUCH_OBJECT, msg);
+          }
+
+          while (!ref.getPropertyValue(tpd)) {
+            boolean isBadReference = true;
+            app.println();
+            if (app.confirmAction(
+                INFO_EDITOR_PROMPT_ENABLED_REFERENCED_COMPONENT.get(rufn, name,
+                    ufn), true)) {
+              ref.setPropertyValue(tpd, true);
+              try {
+                ref.commit();
+                isBadReference = false;
+              } catch (MissingMandatoryPropertiesException e) {
+                // Give the user the chance to fix the problems.
+                app.println();
+                displayMissingMandatoryPropertyException(app, e);
+                app.println();
+                if (app.confirmAction(INFO_DSCFG_PROMPT_EDIT.get(rufn), true)) {
+                  // FIXME: edit the properties of the referenced
+                  // object.
+                  MenuResult<Void> result = SetPropSubCommandHandler
+                      .modifyManagedObject(app, context, ref);
+                  if (result.isQuit()) {
+                    return result;
+                  } else if (result.isSuccess()) {
+                    // The referenced component was modified
+                    // successfully, but may still be disabled.
+                    isBadReference = false;
+                  }
+                }
+              } catch (AuthorizationException e) {
+                Message msg = ERR_DSCFG_ERROR_CREATE_AUTHZ.get(ufn);
+                throw new ClientException(
+                    LDAPResultCode.INSUFFICIENT_ACCESS_RIGHTS, msg);
+              } catch (ConcurrentModificationException e) {
+                Message msg = ERR_DSCFG_ERROR_CREATE_CME.get(ufn);
+                throw new ClientException(LDAPResultCode.CONSTRAINT_VIOLATION,
+                    msg);
+              } catch (OperationRejectedException e) {
+                // Give the user the chance to fix the problems.
+                app.println();
+                displayOperationRejectedException(app, e);
+                app.println();
+                if (app.confirmAction(INFO_DSCFG_PROMPT_EDIT.get(rufn), true)) {
+                  MenuResult<Void> result = SetPropSubCommandHandler
+                      .modifyManagedObject(app, context, ref);
+                  if (result.isQuit()) {
+                    return result;
+                  } else if (result.isSuccess()) {
+                    // The referenced component was modified
+                    // successfully, but may still be disabled.
+                    isBadReference = false;
+                  }
+                }
+              } catch (CommunicationException e) {
+                Message msg = ERR_DSCFG_ERROR_CREATE_CE
+                    .get(ufn, e.getMessage());
+                throw new ClientException(LDAPResultCode.OPERATIONS_ERROR, msg);
+              } catch (ManagedObjectAlreadyExistsException e) {
+                // Should never happen.
+                throw new IllegalStateException(e);
+              }
+            }
+
+            // If the referenced component is still disabled because
+            // the user refused to modify it, then give the used the
+            // option of editing the referencing component.
+            if (isBadReference) {
+              app.println();
+              app.println(ERR_SET_REFERENCED_COMPONENT_DISABLED.get(ufn, rufn));
+              app.println();
+              if (app
+                  .confirmAction(INFO_DSCFG_PROMPT_EDIT_AGAIN.get(ufn), true)) {
+                return MenuResult.again();
+              } else {
+                return MenuResult.cancel();
+              }
+            }
+
+            // If the referenced component is now enabled, then drop out.
+            if (ref.getPropertyValue(tpd)) {
+              break;
+            }
+          }
+        }
+      }
+    }
+
+    return MenuResult.success();
+  }
+
+
+
   // The sub-commands naming arguments.
   private final List<StringArgument> namingArgs;
 
@@ -642,94 +924,16 @@
       setProperty(child, provider, pd);
     }
 
-    while (true) {
-      // Interactively set properties if applicable.
-      if (app.isInteractive()) {
-        SortedSet<PropertyDefinition<?>> properties =
-          new TreeSet<PropertyDefinition<?>>();
-
-        for (PropertyDefinition<?> pd : d.getAllPropertyDefinitions()) {
-          if (pd.hasOption(PropertyOption.HIDDEN)) {
-            continue;
-          }
-
-          if (!app.isAdvancedMode() && pd.hasOption(PropertyOption.ADVANCED)) {
-            continue;
-          }
-
-          properties.add(pd);
-        }
-
-        PropertyValueEditor editor = new PropertyValueEditor(app, context);
-        MenuResult<Void> result2 = editor.edit(child, properties, true);
-        if (result2.isQuit()) {
-          if (!app.isMenuDrivenMode()) {
-            Message msg = INFO_DSCFG_CONFIRM_CREATE_FAIL.get(ufn);
-            app.printVerboseMessage(msg);
-          }
-          return MenuResult.quit();
-        } else if (result2.isCancel()) {
-          return MenuResult.cancel();
-        }
-      }
-
-      try {
-        // Create the managed object.
-        child.commit();
-
-        // Output success message.
-        Message msg = INFO_DSCFG_CONFIRM_CREATE_SUCCESS.get(ufn);
-        app.printVerboseMessage(msg);
-        return MenuResult.success(0);
-      } catch (MissingMandatoryPropertiesException e) {
-        throw ArgumentExceptionFactory.adaptMissingMandatoryPropertiesException(
-            e, d);
-      } catch (AuthorizationException e) {
-        Message msg = ERR_DSCFG_ERROR_CREATE_AUTHZ.get(ufn);
-        throw new ClientException(LDAPResultCode.INSUFFICIENT_ACCESS_RIGHTS,
-            msg);
-      } catch (ManagedObjectAlreadyExistsException e) {
-        Message msg = ERR_DSCFG_ERROR_CREATE_MOAEE.get(ufn);
-        throw new ClientException(LDAPResultCode.ENTRY_ALREADY_EXISTS, msg);
-      } catch (ConcurrentModificationException e) {
-        Message msg = ERR_DSCFG_ERROR_CREATE_CME.get(ufn);
-        throw new ClientException(LDAPResultCode.CONSTRAINT_VIOLATION, msg);
-      } catch (OperationRejectedException e) {
-        Message msg;
-        if (e.getMessages().size() == 1) {
-          msg = ERR_DSCFG_ERROR_CREATE_ORE_SINGLE.get(ufn);
-        } else {
-          msg = ERR_DSCFG_ERROR_CREATE_ORE_PLURAL.get(ufn);
-        }
-
-        if (app.isInteractive()) {
-          // If interactive, give the user the chance to fix the problems.
-          app.println();
-          app.println(msg);
-          app.println();
-          TableBuilder builder = new TableBuilder();
-          for (Message reason : e.getMessages()) {
-            builder.startRow();
-            builder.appendCell("*");
-            builder.appendCell(reason);
-          }
-          TextTablePrinter printer = new TextTablePrinter(app.getErrorStream());
-          printer.setDisplayHeadings(false);
-          printer.setColumnWidth(1, 0);
-          printer.setIndentWidth(4);
-          builder.print(printer);
-          app.println();
-          if (!app.confirmAction(INFO_DSCFG_PROMPT_EDIT_AGAIN.get(ufn), true)) {
-            return MenuResult.cancel();
-          }
-        } else {
-          throw new ClientException(LDAPResultCode.CONSTRAINT_VIOLATION,
-              msg, e);
-        }
-      } catch (CommunicationException e) {
-        Message msg = ERR_DSCFG_ERROR_CREATE_CE.get(ufn, e.getMessage());
-        throw new ClientException(LDAPResultCode.CLIENT_SIDE_SERVER_DOWN, msg);
-      }
+    // Now the command line changes have been made, create the managed
+    // object interacting with the user to fix any problems if
+    // required.
+    MenuResult<Void> result2 = createManagedObject(app, context, child);
+    if (result2.isCancel()) {
+      return MenuResult.cancel();
+    } else if (result2.isQuit()) {
+      return MenuResult.quit();
+    } else {
+      return MenuResult.success(0);
     }
   }
 
diff --git a/opends/src/server/org/opends/server/tools/dsconfig/DSConfig.java b/opends/src/server/org/opends/server/tools/dsconfig/DSConfig.java
index 3092f5f..4d17710 100644
--- a/opends/src/server/org/opends/server/tools/dsconfig/DSConfig.java
+++ b/opends/src/server/org/opends/server/tools/dsconfig/DSConfig.java
@@ -32,6 +32,7 @@
 import static org.opends.messages.ToolMessages.*;
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import static org.opends.server.tools.ToolConstants.*;
+import static org.opends.server.tools.dsconfig.ArgumentExceptionFactory.*;
 import static org.opends.server.util.StaticUtils.*;
 
 import java.io.InputStream;
@@ -45,15 +46,14 @@
 import java.util.TreeSet;
 
 import org.opends.messages.Message;
-import org.opends.server.admin.AbstractManagedObjectDefinition;
 import org.opends.server.admin.AttributeTypePropertyDefinition;
 import org.opends.server.admin.ClassLoaderProvider;
 import org.opends.server.admin.ClassPropertyDefinition;
 import org.opends.server.admin.InstantiableRelationDefinition;
-import org.opends.server.admin.PropertyException;
 import org.opends.server.admin.RelationDefinition;
 import org.opends.server.admin.Tag;
 import org.opends.server.admin.client.ManagedObjectDecodingException;
+import org.opends.server.admin.client.MissingMandatoryPropertiesException;
 import org.opends.server.admin.client.OperationRejectedException;
 import org.opends.server.loggers.debug.DebugTracer;
 import org.opends.server.tools.ClientException;
@@ -72,8 +72,6 @@
 import org.opends.server.util.cli.MenuCallback;
 import org.opends.server.util.cli.MenuResult;
 import org.opends.server.util.cli.OutputStreamConsoleApplication;
-import org.opends.server.util.table.TableBuilder;
-import org.opends.server.util.table.TextTablePrinter;
 
 
 
@@ -826,50 +824,27 @@
       println(e.getMessageObject());
       return 1;
     } catch (ClientException e) {
-      // If the client exception was caused by a decoding exception
-      // then we should display the causes.
-      println(e.getMessageObject());
-
       Throwable cause = e.getCause();
       if (cause instanceof ManagedObjectDecodingException) {
         ManagedObjectDecodingException de =
           (ManagedObjectDecodingException) cause;
-
         println();
-        TableBuilder builder = new TableBuilder();
-        for (PropertyException pe : de.getCauses()) {
-          AbstractManagedObjectDefinition<?, ?> d = de
-              .getPartialManagedObject().getManagedObjectDefinition();
-          ArgumentException ae = ArgumentExceptionFactory
-              .adaptPropertyException(pe, d);
-          builder.startRow();
-          builder.appendCell("*");
-          builder.appendCell(ae.getMessage());
-        }
-
-        TextTablePrinter printer = new TextTablePrinter(getErrorStream());
-        printer.setDisplayHeadings(false);
-        printer.setColumnWidth(1, 0);
-        printer.setIndentWidth(4);
-        builder.print(printer);
+        displayManagedObjectDecodingException(this, de);
+        println();
+      } else if (cause instanceof MissingMandatoryPropertiesException) {
+        MissingMandatoryPropertiesException mmpe =
+          (MissingMandatoryPropertiesException) cause;
+        println();
+        displayMissingMandatoryPropertyException(this, mmpe);
         println();
       } else if (cause instanceof OperationRejectedException) {
         OperationRejectedException ore = (OperationRejectedException) cause;
-
         println();
-        TableBuilder builder = new TableBuilder();
-        for (Message reason : ore.getMessages()) {
-          builder.startRow();
-          builder.appendCell("*");
-          builder.appendCell(reason);
-        }
-
-        TextTablePrinter printer = new TextTablePrinter(getErrorStream());
-        printer.setDisplayHeadings(false);
-        printer.setColumnWidth(1, 0);
-        printer.setIndentWidth(4);
-        builder.print(printer);
+        displayOperationRejectedException(this, ore);
         println();
+      } else {
+        // Just display the default message.
+        println(e.getMessageObject());
       }
 
       return 1;
diff --git a/opends/src/server/org/opends/server/tools/dsconfig/SetPropSubCommandHandler.java b/opends/src/server/org/opends/server/tools/dsconfig/SetPropSubCommandHandler.java
index 30b1105..73e5b43 100644
--- a/opends/src/server/org/opends/server/tools/dsconfig/SetPropSubCommandHandler.java
+++ b/opends/src/server/org/opends/server/tools/dsconfig/SetPropSubCommandHandler.java
@@ -29,6 +29,7 @@
 
 
 import static org.opends.messages.DSConfigMessages.*;
+import static org.opends.server.tools.dsconfig.ArgumentExceptionFactory.*;
 
 import java.util.HashMap;
 import java.util.List;
@@ -38,6 +39,8 @@
 import java.util.TreeSet;
 
 import org.opends.messages.Message;
+import org.opends.server.admin.AggregationPropertyDefinition;
+import org.opends.server.admin.BooleanPropertyDefinition;
 import org.opends.server.admin.DefinitionDecodingException;
 import org.opends.server.admin.IllegalPropertyValueStringException;
 import org.opends.server.admin.InstantiableRelationDefinition;
@@ -69,8 +72,6 @@
 import org.opends.server.util.cli.CLIException;
 import org.opends.server.util.cli.ConsoleApplication;
 import org.opends.server.util.cli.MenuResult;
-import org.opends.server.util.table.TableBuilder;
-import org.opends.server.util.table.TextTablePrinter;
 
 
 
@@ -83,7 +84,7 @@
 final class SetPropSubCommandHandler extends SubCommandHandler {
 
   /**
-   * Type of modication being performed.
+   * Type of modification being performed.
    */
   private static enum ModificationType {
     /**
@@ -207,6 +208,285 @@
     return new SetPropSubCommandHandler(parser, path.child(r), r);
   }
 
+
+
+  /**
+   * Configure the provided managed object.
+   *
+   * @param app
+   *          The console application.
+   * @param context
+   *          The management context.
+   * @param mo
+   *          The managed object to be configured.
+   * @return Returns a MenuResult.success() if the managed object was
+   *         configured successfully, or MenuResult.quit(), or
+   *         MenuResult.cancel(), if the managed object was edited
+   *         interactively and the user chose to quit or cancel.
+   * @throws ClientException
+   *           If an unrecoverable client exception occurred whilst
+   *           interacting with the server.
+   * @throws CLIException
+   *           If an error occurred whilst interacting with the
+   *           console.
+   */
+  public static MenuResult<Void> modifyManagedObject(ConsoleApplication app,
+      ManagementContext context, ManagedObject<?> mo) throws ClientException,
+      CLIException {
+    ManagedObjectDefinition<?, ?> d = mo.getManagedObjectDefinition();
+    Message ufn = d.getUserFriendlyName();
+
+    while (true) {
+      // Interactively set properties if applicable.
+      if (app.isInteractive()) {
+        SortedSet<PropertyDefinition<?>> properties =
+          new TreeSet<PropertyDefinition<?>>();
+        for (PropertyDefinition<?> pd : d.getAllPropertyDefinitions()) {
+          if (pd.hasOption(PropertyOption.HIDDEN)) {
+            continue;
+          }
+          if (!app.isAdvancedMode() && pd.hasOption(PropertyOption.ADVANCED)) {
+            continue;
+          }
+          properties.add(pd);
+        }
+
+        PropertyValueEditor editor = new PropertyValueEditor(app, context);
+        MenuResult<Void> result = editor.edit(mo, properties, false);
+
+        // Interactively enable/edit referenced components.
+        if (result.isSuccess()) {
+          result = checkReferences(app, context, mo);
+          if (result.isAgain()) {
+            // Edit again.
+            continue;
+          }
+        }
+
+        if (result.isQuit()) {
+          if (!app.isMenuDrivenMode()) {
+            // User chose to cancel any changes.
+            Message msg = INFO_DSCFG_CONFIRM_MODIFY_FAIL.get(ufn);
+            app.printVerboseMessage(msg);
+          }
+          return MenuResult.quit();
+        } else if (result.isCancel()) {
+          return MenuResult.cancel();
+        }
+      }
+
+      try {
+        // Commit the changes.
+        mo.commit();
+
+        // Output success message.
+        app.println();
+        Message msg = INFO_DSCFG_CONFIRM_MODIFY_SUCCESS.get(ufn);
+        app.printVerboseMessage(msg);
+
+        return MenuResult.success();
+      } catch (MissingMandatoryPropertiesException e) {
+        if (app.isInteractive()) {
+          // If interactive, give the user the chance to fix the
+          // problems.
+          app.println();
+          displayMissingMandatoryPropertyException(app, e);
+          app.println();
+          if (!app.confirmAction(INFO_DSCFG_PROMPT_EDIT_AGAIN.get(ufn), true)) {
+            return MenuResult.cancel();
+          }
+        } else {
+          throw new ClientException(LDAPResultCode.CONSTRAINT_VIOLATION, e
+              .getMessageObject(), e);
+        }
+      } catch (AuthorizationException e) {
+        Message msg = ERR_DSCFG_ERROR_MODIFY_AUTHZ.get(ufn);
+        throw new ClientException(LDAPResultCode.INSUFFICIENT_ACCESS_RIGHTS,
+            msg);
+      } catch (ConcurrentModificationException e) {
+        Message msg = ERR_DSCFG_ERROR_MODIFY_CME.get(ufn);
+        throw new ClientException(LDAPResultCode.CONSTRAINT_VIOLATION, msg);
+      } catch (OperationRejectedException e) {
+        if (app.isInteractive()) {
+          // If interactive, give the user the chance to fix the
+          // problems.
+          app.println();
+          displayOperationRejectedException(app, e);
+          app.println();
+          if (!app.confirmAction(INFO_DSCFG_PROMPT_EDIT_AGAIN.get(ufn), true)) {
+            return MenuResult.cancel();
+          }
+        } else {
+          throw new ClientException(LDAPResultCode.CONSTRAINT_VIOLATION, e
+              .getMessageObject(), e);
+        }
+      } catch (CommunicationException e) {
+        Message msg = ERR_DSCFG_ERROR_MODIFY_CE.get(ufn, e.getMessage());
+        throw new ClientException(LDAPResultCode.OPERATIONS_ERROR, msg);
+      } catch (ManagedObjectAlreadyExistsException e) {
+        // Should never happen.
+        throw new IllegalStateException(e);
+      }
+    }
+  }
+
+
+
+  // Check that any referenced components are enabled if
+  // required.
+  private static MenuResult<Void> checkReferences(ConsoleApplication app,
+      ManagementContext context, ManagedObject<?> mo) throws ClientException,
+      CLIException {
+    ManagedObjectDefinition<?, ?> d = mo.getManagedObjectDefinition();
+    Message ufn = d.getUserFriendlyName();
+
+    for (PropertyDefinition<?> pd : d.getAllPropertyDefinitions()) {
+      if (pd instanceof AggregationPropertyDefinition) {
+        AggregationPropertyDefinition<?, ?> apd =
+          (AggregationPropertyDefinition<?, ?>) pd;
+
+        // Skip this aggregation if it doesn't have an enable
+        // property.
+        BooleanPropertyDefinition tpd = apd
+            .getTargetEnabledPropertyDefinition();
+        if (tpd == null) {
+          continue;
+        }
+
+        // Skip this aggregation if this managed object's enable
+        // properties are not all true.
+        boolean needsEnabling = true;
+        for (BooleanPropertyDefinition bpd : apd
+            .getSourceEnabledPropertyDefinitions()) {
+          if (!mo.getPropertyValue(bpd)) {
+            needsEnabling = false;
+            break;
+          }
+        }
+        if (!needsEnabling) {
+          continue;
+        }
+
+        // The referenced component(s) must be enabled.
+        for (String name : mo.getPropertyValues(apd)) {
+          ManagedObjectPath<?, ?> path = apd.getChildPath(name);
+          Message rufn = path.getManagedObjectDefinition()
+              .getUserFriendlyName();
+          ManagedObject<?> ref;
+          try {
+            ref = context.getManagedObject(path);
+          } catch (AuthorizationException e) {
+            Message msg = ERR_DSCFG_ERROR_MODIFY_AUTHZ.get(ufn);
+            throw new ClientException(
+                LDAPResultCode.INSUFFICIENT_ACCESS_RIGHTS, msg);
+          } catch (DefinitionDecodingException e) {
+            Message msg = ERR_DSCFG_ERROR_GET_CHILD_DDE.get(rufn, rufn, rufn);
+            throw new ClientException(LDAPResultCode.OPERATIONS_ERROR, msg);
+          } catch (ManagedObjectDecodingException e) {
+            // FIXME: should not abort here. Instead, display the
+            // errors (if verbose) and apply the changes to the
+            // partial managed object.
+            Message msg = ERR_DSCFG_ERROR_GET_CHILD_MODE.get(rufn);
+            throw new ClientException(LDAPResultCode.OPERATIONS_ERROR, msg, e);
+          } catch (CommunicationException e) {
+            Message msg = ERR_DSCFG_ERROR_MODIFY_CE.get(ufn, e.getMessage());
+            throw new ClientException(LDAPResultCode.OPERATIONS_ERROR, msg);
+          } catch (ManagedObjectNotFoundException e) {
+            Message msg = ERR_DSCFG_ERROR_GET_CHILD_MONFE.get(rufn);
+            throw new ClientException(LDAPResultCode.NO_SUCH_OBJECT, msg);
+          }
+
+          while (!ref.getPropertyValue(tpd)) {
+            boolean isBadReference = true;
+            app.println();
+            if (app.confirmAction(
+                INFO_EDITOR_PROMPT_ENABLED_REFERENCED_COMPONENT.get(rufn, name,
+                    ufn), true)) {
+              ref.setPropertyValue(tpd, true);
+              try {
+                ref.commit();
+                isBadReference = false;
+              } catch (MissingMandatoryPropertiesException e) {
+                // Give the user the chance to fix the problems.
+                app.println();
+                displayMissingMandatoryPropertyException(app, e);
+                app.println();
+                if (app.confirmAction(INFO_DSCFG_PROMPT_EDIT.get(rufn), true)) {
+                  // FIXME: edit the properties of the referenced
+                  // object.
+                  MenuResult<Void> result =
+                    modifyManagedObject(app, context, ref);
+                  if (result.isQuit()) {
+                    return result;
+                  } else if (result.isSuccess()) {
+                    // The referenced component was modified
+                    // successfully, but may still be disabled.
+                    isBadReference = false;
+                  }
+                }
+              } catch (AuthorizationException e) {
+                Message msg = ERR_DSCFG_ERROR_MODIFY_AUTHZ.get(ufn);
+                throw new ClientException(
+                    LDAPResultCode.INSUFFICIENT_ACCESS_RIGHTS, msg);
+              } catch (ConcurrentModificationException e) {
+                Message msg = ERR_DSCFG_ERROR_MODIFY_CME.get(ufn);
+                throw new ClientException(LDAPResultCode.CONSTRAINT_VIOLATION,
+                    msg);
+              } catch (OperationRejectedException e) {
+                // Give the user the chance to fix the problems.
+                app.println();
+                displayOperationRejectedException(app, e);
+                app.println();
+                if (app.confirmAction(INFO_DSCFG_PROMPT_EDIT.get(rufn), true)) {
+                  MenuResult<Void> result =
+                    modifyManagedObject(app, context, ref);
+                  if (result.isQuit()) {
+                    return result;
+                  } else if (result.isSuccess()) {
+                    // The referenced component was modified
+                    // successfully, but may still be disabled.
+                    isBadReference = false;
+                  }
+                }
+              } catch (CommunicationException e) {
+                Message msg = ERR_DSCFG_ERROR_MODIFY_CE
+                    .get(ufn, e.getMessage());
+                throw new ClientException(LDAPResultCode.OPERATIONS_ERROR, msg);
+              } catch (ManagedObjectAlreadyExistsException e) {
+                // Should never happen.
+                throw new IllegalStateException(e);
+              }
+            }
+
+            // If the referenced component is still disabled because
+            // the user refused to modify it, then give the used the
+            // option of editing the referencing component.
+            if (isBadReference) {
+              app.println();
+              app.println(ERR_SET_REFERENCED_COMPONENT_DISABLED.get(ufn, rufn));
+              app.println();
+              if (app
+                  .confirmAction(INFO_DSCFG_PROMPT_EDIT_AGAIN.get(ufn), true)) {
+                return MenuResult.again();
+              } else {
+                return MenuResult.cancel();
+              }
+            }
+
+            // If the referenced component is now enabled, then drop out.
+            if (ref.getPropertyValue(tpd)) {
+              break;
+            }
+          }
+        }
+      }
+    }
+
+    return MenuResult.success();
+  }
+
+
+
   // The sub-commands naming arguments.
   private final List<StringArgument> namingArgs;
 
@@ -509,96 +789,15 @@
       }
     }
 
-    while (true) {
-      // Interactively set properties if applicable.
-      if (app.isInteractive()) {
-        SortedSet<PropertyDefinition<?>> properties =
-          new TreeSet<PropertyDefinition<?>>();
-
-        for (PropertyDefinition<?> pd : d.getAllPropertyDefinitions()) {
-          if (pd.hasOption(PropertyOption.HIDDEN)) {
-            continue;
-          }
-
-          if (!app.isAdvancedMode() && pd.hasOption(PropertyOption.ADVANCED)) {
-            continue;
-          }
-
-          properties.add(pd);
-        }
-
-        PropertyValueEditor editor = new PropertyValueEditor(app, context);
-        MenuResult<Void> result2 = editor.edit(child, properties, false);
-        if (result2.isQuit()) {
-          if (!app.isMenuDrivenMode()) {
-            // User chose to cancel any changes.
-            Message msg = INFO_DSCFG_CONFIRM_MODIFY_FAIL.get(ufn);
-            app.printVerboseMessage(msg);
-          }
-          return MenuResult.quit();
-        } else if (result2.isCancel()) {
-          return MenuResult.cancel();
-        }
-      }
-
-      try {
-        // Commit the changes.
-        child.commit();
-
-        // Output success message.
-        Message msg = INFO_DSCFG_CONFIRM_MODIFY_SUCCESS.get(ufn);
-        app.printVerboseMessage(msg);
-
-        return MenuResult.success(0);
-      } catch (MissingMandatoryPropertiesException e) {
-        throw ArgumentExceptionFactory
-            .adaptMissingMandatoryPropertiesException(e, d);
-      } catch (AuthorizationException e) {
-        Message msg = ERR_DSCFG_ERROR_MODIFY_AUTHZ.get(ufn);
-        throw new ClientException(LDAPResultCode.INSUFFICIENT_ACCESS_RIGHTS,
-            msg);
-      } catch (ConcurrentModificationException e) {
-        Message msg = ERR_DSCFG_ERROR_MODIFY_CME.get(ufn);
-        throw new ClientException(LDAPResultCode.CONSTRAINT_VIOLATION, msg);
-      } catch (OperationRejectedException e) {
-        Message msg;
-        if (e.getMessages().size() == 1) {
-          msg = ERR_DSCFG_ERROR_MODIFY_ORE_SINGLE.get(ufn);
-        } else {
-          msg = ERR_DSCFG_ERROR_MODIFY_ORE_PLURAL.get(ufn);
-        }
-
-        if (app.isInteractive()) {
-          // If interactive, give the user the chance to fix the problems.
-          app.println();
-          app.println(msg);
-          app.println();
-          TableBuilder builder = new TableBuilder();
-          for (Message reason : e.getMessages()) {
-            builder.startRow();
-            builder.appendCell("*");
-            builder.appendCell(reason);
-          }
-          TextTablePrinter printer = new TextTablePrinter(app.getErrorStream());
-          printer.setDisplayHeadings(false);
-          printer.setColumnWidth(1, 0);
-          printer.setIndentWidth(4);
-          builder.print(printer);
-          app.println();
-          if (!app.confirmAction(INFO_DSCFG_PROMPT_EDIT_AGAIN.get(ufn), true)) {
-            return MenuResult.cancel();
-          }
-        } else {
-          throw new ClientException(LDAPResultCode.CONSTRAINT_VIOLATION,
-              msg, e);
-        }
-      } catch (CommunicationException e) {
-        Message msg = ERR_DSCFG_ERROR_MODIFY_CE.get(ufn, e.getMessage());
-        throw new ClientException(LDAPResultCode.OPERATIONS_ERROR, msg);
-      } catch (ManagedObjectAlreadyExistsException e) {
-        // Should never happen.
-        throw new IllegalStateException(e);
-      }
+    // Now the command line changes have been made, apply the changes
+    // interacting with the user to fix any problems if required.
+    MenuResult<Void> result2 = modifyManagedObject(app, context, child);
+    if (result2.isCancel()){
+      return MenuResult.cancel();
+    } else if (result2.isQuit()) {
+      return MenuResult.quit();
+    } else {
+      return MenuResult.success(0);
     }
   }
 

--
Gitblit v1.10.0