mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

matthew_swift
19.31.2007 8228fb82f3ad657adf7832eb05c624bf48c4a30e
More changes relating to issue 1449: aggregation support.

This change adds some niceness to dsconfig so that it will ask users if they want to enable a referenced component which is currently disabled. If the user says yes, dsconfig will enable the referenced component and commit the change. If this fails (e.g. the current state of the component means that it cannot be enabled), the user is given the opportunity to edit the properties of the component in order to fix the problems. Users a free to cancel out at any moment.

As part of this change I also refactored some of the error handling. One advantage of this is that if a problem occurs while using dsconfig non-interactively, more helpful messages will be displayed in certain situations. For example, if there are missing mandatory properties, a table is displayed showing the mandatory properties and their syntax.
11 files modified
1193 ■■■■ changed files
opends/src/messages/messages/dsconfig.properties 17 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/admin/client/MissingMandatoryPropertiesException.java 46 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/admin/client/OperationRejectedException.java 81 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/admin/client/ldap/LDAPDriver.java 9 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/admin/client/ldap/LDAPManagedObject.java 30 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/admin/client/spi/AbstractManagedObject.java 12 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/admin/client/spi/Driver.java 4 ●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/dsconfig/ArgumentExceptionFactory.java 178 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/dsconfig/CreateSubCommandHandler.java 380 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/dsconfig/DSConfig.java 51 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/dsconfig/SetPropSubCommandHandler.java 385 ●●●● patch | view | raw | blame | history
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:
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;
  }
}
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;
  }
}
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);
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.
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.
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);
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.
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);
    }
  }
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;
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);
    }
  }