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

matthew_swift
19.16.2007 00e13f972c166b2d849c8f7c72ee5c60330ef7e5
Partial fix for issue 1449: add support in dsconfig for dynamically creating new components when editing aggregation properties.
3 files modified
769 ■■■■■ changed files
opends/src/messages/messages/dsconfig.properties 1 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/dsconfig/CreateSubCommandHandler.java 667 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/dsconfig/PropertyValueEditor.java 101 ●●●●● patch | view | raw | blame | history
opends/src/messages/messages/dsconfig.properties
@@ -439,3 +439,4 @@
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:
INFO_EDITOR_OPTION_CREATE_A_NEW_COMPONENT_145=Create a new %s
opends/src/server/org/opends/server/tools/dsconfig/CreateSubCommandHandler.java
@@ -83,7 +83,6 @@
import org.opends.server.util.cli.CLIException;
import org.opends.server.util.cli.ConsoleApplication;
import org.opends.server.util.cli.HelpCallback;
import org.opends.server.util.cli.Menu;
import org.opends.server.util.cli.MenuBuilder;
import org.opends.server.util.cli.MenuResult;
import org.opends.server.util.cli.ValidationCallback;
@@ -233,7 +232,21 @@
   * A help call-back which displays help about available component
   * types.
   */
  private final class TypeHelpCallback implements HelpCallback {
  private static final class TypeHelpCallback
      <C extends ConfigurationClient, S extends Configuration>
      implements HelpCallback {
    // The abstract definition for which to provide help on its sub-types.
    private final AbstractManagedObjectDefinition<C, S> d;
    // Create a new type help call-back.
    private TypeHelpCallback(AbstractManagedObjectDefinition<C, S> d) {
      this.d = d;
    }
    /**
     * {@inheritDoc}
@@ -250,7 +263,7 @@
          .get());
      boolean isFirst = true;
      for (ManagedObjectDefinition<?, ?> d : types.values()) {
      for (ManagedObjectDefinition<?, ?> mod : getSubTypes(d).values()) {
        if (!isFirst) {
          builder.startRow();
          builder.startRow();
@@ -259,13 +272,13 @@
        }
        builder.startRow();
        builder.appendCell(d.getUserFriendlyName());
        builder.appendCell(d.getSynopsis());
        if (d.getDescription() != null) {
        builder.appendCell(mod.getUserFriendlyName());
        builder.appendCell(mod.getSynopsis());
        if (mod.getDescription() != null) {
          builder.startRow();
          builder.startRow();
          builder.appendCell();
          builder.appendCell(d.getDescription());
          builder.appendCell(mod.getDescription());
        }
      }
@@ -278,6 +291,8 @@
    }
  }
  /**
   * The value for the -t argument which will be used for the most
   * generic managed object when it is instantiable.
@@ -361,18 +376,27 @@
  /**
   * Create the provided managed object.
   * Interactively lets a user create a new managed object beneath a
   * parent.
   *
   * @param <C>
   *          The type of managed object which can be created.
   * @param <S>
   *          The type of server managed object which can be created.
   * @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.
   * @param parent
   *          The parent managed object.
   * @param rd
   *          The relation beneath which the child managed object
   *          should be created.
   * @return Returns a MenuResult.success() containing the name of the
   *         created managed object if it 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.
@@ -380,103 +404,43 @@
   *           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();
  public static <C extends ConfigurationClient, S extends Configuration>
      MenuResult<String> createManagedObject(
      ConsoleApplication app, ManagementContext context,
      ManagedObject<?> parent, InstantiableRelationDefinition<C, S> rd)
      throws ClientException, CLIException {
    AbstractManagedObjectDefinition<C, S> d = rd.getChildDefinition();
    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);
        }
    // First determine what type of component the user wants to create.
    MenuResult<ManagedObjectDefinition<? extends C, ? extends S>> result;
    result = getTypeInteractively(app, d);
        PropertyValueEditor editor = new PropertyValueEditor(app, context);
        MenuResult<Void> result = editor.edit(mo, properties, false);
    ManagedObjectDefinition<? extends C, ? extends S> mod;
    if (result.isSuccess()) {
      mod = result.getValue();
    } else if (result.isCancel()) {
      return MenuResult.cancel();
    } else {
      return MenuResult.quit();
    }
        // Interactively enable/edit referenced components.
        if (result.isSuccess()) {
          result = checkReferences(app, context, mo);
          if (result.isAgain()) {
            // Edit again.
            continue;
          }
        }
    // Now create the component.
    // FIXME: handle default value exceptions?
    List<DefaultBehaviorException> exceptions =
      new LinkedList<DefaultBehaviorException>();
    app.println();
    app.println();
    ManagedObject<? extends C> mo =
      createChildInteractively(app, parent, rd, mod, exceptions);
        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);
      }
    // Let the user interactively configure the managed object and commit it.
    MenuResult<Void> result2 = commitManagedObject(app, context, mo);
    if (result2.isCancel()) {
      return MenuResult.cancel();
    } else if (result2.isQuit()) {
      return MenuResult.quit();
    } else {
      return MenuResult.success(mo.getManagedObjectPath().getName());
    }
  }
@@ -637,6 +601,286 @@
  // Commit a new managed object's configuration.
  private static MenuResult<Void> commitManagedObject(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);
      }
    }
  }
  // Interactively create the child by prompting for the name.
  private static <C extends ConfigurationClient, S extends Configuration>
  ManagedObject<? extends C> createChildInteractively(
      ConsoleApplication app, final ManagedObject<?> parent,
      final InstantiableRelationDefinition<C, S> irelation,
      final ManagedObjectDefinition<? extends C, ? extends S> d,
      final List<DefaultBehaviorException> exceptions) throws CLIException {
    ValidationCallback<ManagedObject<? extends C>> validator =
      new ValidationCallback<ManagedObject<? extends C>>() {
      public ManagedObject<? extends C> validate(ConsoleApplication app,
          String input) throws CLIException {
        ManagedObject<? extends C> child;
        // First attempt to create the child, this will guarantee that
        // the name is acceptable.
        try {
          child = parent.createChild(irelation, d, input, exceptions);
        } catch (IllegalManagedObjectNameException e) {
          CLIException ae = ArgumentExceptionFactory
              .adaptIllegalManagedObjectNameException(e, d);
          app.println();
          app.println(ae.getMessageObject());
          app.println();
          return null;
        }
        // Make sure that there are not any other children with the
        // same name.
        try {
          // Attempt to retrieve a child using this name.
          parent.getChild(irelation, input);
        } catch (AuthorizationException e) {
          Message msg = ERR_DSCFG_ERROR_CREATE_AUTHZ.get(irelation
              .getUserFriendlyName());
          throw new CLIException(msg);
        } catch (ConcurrentModificationException e) {
          Message msg = ERR_DSCFG_ERROR_CREATE_CME.get(irelation
              .getUserFriendlyName());
          throw new CLIException(msg);
        } catch (CommunicationException e) {
          Message msg = ERR_DSCFG_ERROR_CREATE_CE.get(irelation
              .getUserFriendlyName(), e.getMessage());
          throw new CLIException(msg);
        } catch (DefinitionDecodingException e) {
          // Do nothing.
        } catch (ManagedObjectDecodingException e) {
          // Do nothing.
        } catch (ManagedObjectNotFoundException e) {
          // The child does not already exist so this name is ok.
          return child;
        }
        // A child with the specified name must already exist.
        Message msg = ERR_DSCFG_ERROR_CREATE_NAME_ALREADY_EXISTS.get(irelation
            .getUserFriendlyName(), input);
        app.println();
        app.println(msg);
        app.println();
        return null;
      }
    };
    // Display additional help if the name is a naming property.
    Message ufn = d.getUserFriendlyName();
    PropertyDefinition<?> pd = irelation.getNamingPropertyDefinition();
    if (pd != null) {
      app.println(INFO_DSCFG_CREATE_NAME_PROMPT_NAMING.get(ufn, pd.getName()));
      app.println();
      app.println(pd.getSynopsis(), 4);
      if (pd.getDescription() != null) {
        app.println();
        app.println(pd.getDescription(), 4);
      }
      PropertyDefinitionUsageBuilder b = new PropertyDefinitionUsageBuilder(
          true);
      app.println();
      app.println(INFO_EDITOR_HEADING_SYNTAX.get(b.getUsage(pd)), 4);
      app.println();
      return app.readValidatedInput(INFO_DSCFG_CREATE_NAME_PROMPT_NAMING_CONT
          .get(ufn), validator);
    } else {
      return app.readValidatedInput(INFO_DSCFG_CREATE_NAME_PROMPT.get(ufn),
          validator);
    }
  }
  // Generate the type name - definition mapping table.
  @SuppressWarnings("unchecked")
  private static <C extends ConfigurationClient, S extends Configuration>
  SortedMap<String, ManagedObjectDefinition<? extends C, ? extends S>>
      getSubTypes(AbstractManagedObjectDefinition<C, S> d) {
    SortedMap<String, ManagedObjectDefinition<? extends C, ? extends S>> map;
    map =
      new TreeMap<String, ManagedObjectDefinition<? extends C, ? extends S>>();
    // If the top-level definition is instantiable, we use the value
    // "generic".
    if (d instanceof ManagedObjectDefinition) {
      ManagedObjectDefinition<? extends C, ? extends S> mod =
        (ManagedObjectDefinition<? extends C, ? extends S>) d;
      map.put(GENERIC_TYPE, mod);
    }
    // Process its sub-definitions.
    String suffix = "-" + d.getName();
    for (AbstractManagedObjectDefinition<? extends C, ? extends S> c : d
        .getAllChildren()) {
      if (c instanceof ManagedObjectDefinition) {
        ManagedObjectDefinition<? extends C, ? extends S> mod =
          (ManagedObjectDefinition<? extends C, ? extends S>) c;
        // For the type name we shorten it, if possible, by stripping
        // off the trailing part of the name which matches the
        // base-type.
        String name = mod.getName();
        if (name.endsWith(suffix)) {
          name = name.substring(0, name.length() - suffix.length());
        }
        map.put(name, mod);
      }
    }
    return map;
  }
  // Interactively ask the user which type of component they want to create.
  private static <C extends ConfigurationClient, S extends Configuration>
      MenuResult<ManagedObjectDefinition<? extends C, ? extends S>>
      getTypeInteractively(ConsoleApplication app,
          AbstractManagedObjectDefinition<C, S> d) throws CLIException {
    Collection<ManagedObjectDefinition<? extends C, ? extends S>> types;
    types = getSubTypes(d).values();
    // If there is only one choice then return immediately.
    if (types.size() == 1) {
      ManagedObjectDefinition<? extends C, ? extends S> type =
        types.iterator().next();
      return MenuResult.<ManagedObjectDefinition<? extends C,
          ? extends S>>success(type);
    } else {
      MenuBuilder<ManagedObjectDefinition<? extends C, ? extends S>> builder =
        new MenuBuilder<ManagedObjectDefinition<? extends C, ? extends S>>(app);
      Message msg = INFO_DSCFG_CREATE_TYPE_PROMPT.get(d.getUserFriendlyName());
      builder.setMultipleColumnThreshold(MULTI_COLUMN_THRESHOLD);
      builder.setPrompt(msg);
      for (ManagedObjectDefinition<? extends C, ? extends S> mod : types) {
        Message option = mod.getUserFriendlyName();
        if ((mod == d) && (mod instanceof ManagedObjectDefinition)) {
          option = INFO_DSCFG_GENERIC_TYPE_OPTION.get(option);
        }
        builder.addNumberedOption(option,
            MenuResult.<ManagedObjectDefinition<? extends C,
                ? extends S>>success(mod));
      }
      builder.addHelpOption(new TypeHelpCallback<C,S>(d));
      if (app.isMenuDrivenMode()) {
        builder.addCancelOption(true);
      }
      builder.addQuitOption();
      return builder.toMenu().run();
    }
  }
  // The sub-commands naming arguments.
  private final List<StringArgument> namingArgs;
@@ -770,69 +1014,41 @@
      ManagementContextFactory factory) throws ArgumentException,
      ClientException, CLIException {
    // Determine the type of managed object to be created.
    String typeName;
    ManagedObjectDefinition<? extends C, ? extends S> d;
    if (!typeArgument.isPresent()) {
      if (app.isInteractive()) {
        // Let the user choose.
        MenuResult<ManagedObjectDefinition<? extends C, ? extends S>> result;
        app.println();
        app.println();
        result = getTypeInteractively(app, relation.getChildDefinition());
        // If there is only one choice then return immediately.
        if (types.size() == 1) {
          typeName = types.keySet().iterator().next();
        if (result.isSuccess()) {
          d = result.getValue();
        } else if (result.isCancel()) {
          return MenuResult.cancel();
        } else {
          MenuBuilder<String> builder = new MenuBuilder<String>(app);
          Message msg = INFO_DSCFG_CREATE_TYPE_PROMPT.get(relation
              .getChildDefinition().getUserFriendlyName());
          builder.setMultipleColumnThreshold(MULTI_COLUMN_THRESHOLD);
          builder.setPrompt(msg);
          for (String type : types.keySet()) {
            ManagedObjectDefinition<?, ?> d = types.get(type);
            Message option = d.getUserFriendlyName();
            if (type.equals(GENERIC_TYPE)) {
              option = INFO_DSCFG_GENERIC_TYPE_OPTION.get(option);
            }
            builder.addNumberedOption(option, MenuResult.success(type));
          // Must be quit.
          if (!app.isMenuDrivenMode()) {
            app.printVerboseMessage(INFO_DSCFG_CONFIRM_CREATE_FAIL.get(relation
                .getUserFriendlyName()));
          }
          builder.addHelpOption(new TypeHelpCallback());
          if (app.isMenuDrivenMode()) {
            builder.addCancelOption(true);
          }
          builder.addQuitOption();
          Menu<String> menu = builder.toMenu();
          app.println();
          app.println();
          MenuResult<String> result = menu.run();
          if (result.isSuccess()) {
            typeName = result.getValue();
          } else if (result.isCancel()) {
            return MenuResult.cancel();
          } else {
            // Must be quit.
            if (!app.isMenuDrivenMode()) {
              msg = INFO_DSCFG_CONFIRM_CREATE_FAIL.get(relation
                  .getUserFriendlyName());
              app.printVerboseMessage(msg);
            }
            return MenuResult.quit();
          }
          return MenuResult.quit();
        }
      } else if (typeArgument.getDefaultValue() != null) {
        typeName = typeArgument.getDefaultValue();
        d = types.get(typeArgument.getDefaultValue());
      } else {
        throw ArgumentExceptionFactory
            .missingMandatoryNonInteractiveArgument(typeArgument);
      }
    } else {
      typeName = typeArgument.getValue();
      d = types.get(typeArgument.getValue());
      if (d == null) {
        throw ArgumentExceptionFactory.unknownSubType(relation, typeArgument
            .getValue(), typeUsage);
      }
    }
    ManagedObjectDefinition<? extends C, ? extends S> d = types.get(typeName);
    if (d == null) {
      throw ArgumentExceptionFactory.unknownSubType(relation, typeName,
          typeUsage);
    }
    Message ufn = d.getUserFriendlyName();
    // Get the naming argument values.
@@ -894,6 +1110,8 @@
      String name = names.get(names.size() - 1);
      if (name == null) {
        if (app.isInteractive()) {
          app.println();
          app.println();
          child = createChildInteractively(app, parent, irelation,
              d, exceptions);
        } else {
@@ -927,7 +1145,7 @@
    // 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);
    MenuResult<Void> result2 = commitManagedObject(app, context, child);
    if (result2.isCancel()) {
      return MenuResult.cancel();
    } else if (result2.isQuit()) {
@@ -939,143 +1157,6 @@
  // Interactively create the child by prompting for the name.
  private ManagedObject<? extends C> createChildInteractively(
      ConsoleApplication app, final ManagedObject<?> parent,
      final InstantiableRelationDefinition<C, S> irelation,
      final ManagedObjectDefinition<? extends C, ? extends S> d,
      final List<DefaultBehaviorException> exceptions) throws CLIException {
    ValidationCallback<ManagedObject<? extends C>> validator =
      new ValidationCallback<ManagedObject<? extends C>>() {
      public ManagedObject<? extends C> validate(ConsoleApplication app,
          String input) throws CLIException {
        ManagedObject<? extends C> child;
        // First attempt to create the child, this will guarantee that
        // the name is acceptable.
        try {
          child = parent.createChild(irelation, d, input, exceptions);
        } catch (IllegalManagedObjectNameException e) {
          CLIException ae = ArgumentExceptionFactory
              .adaptIllegalManagedObjectNameException(e, d);
          app.println();
          app.println(ae.getMessageObject());
          app.println();
          return null;
        }
        // Make sure that there are not any other children with the
        // same name.
        try {
          // Attempt to retrieve a child using this name.
          parent.getChild(irelation, input);
        } catch (AuthorizationException e) {
          Message msg = ERR_DSCFG_ERROR_CREATE_AUTHZ.get(irelation
              .getUserFriendlyName());
          throw new CLIException(msg);
        } catch (ConcurrentModificationException e) {
          Message msg = ERR_DSCFG_ERROR_CREATE_CME.get(irelation
              .getUserFriendlyName());
          throw new CLIException(msg);
        } catch (CommunicationException e) {
          Message msg = ERR_DSCFG_ERROR_CREATE_CE.get(irelation
              .getUserFriendlyName(), e.getMessage());
          throw new CLIException(msg);
        } catch (DefinitionDecodingException e) {
          // Do nothing.
        } catch (ManagedObjectDecodingException e) {
          // Do nothing.
        } catch (ManagedObjectNotFoundException e) {
          // The child does not already exist so this name is ok.
          return child;
        }
        // A child with the specified name must already exist.
        Message msg = ERR_DSCFG_ERROR_CREATE_NAME_ALREADY_EXISTS.get(relation
            .getUserFriendlyName(), input);
        app.println();
        app.println(msg);
        app.println();
        return null;
      }
    };
    app.println();
    app.println();
    // Display additional help if the name is a naming property.
    Message ufn = d.getUserFriendlyName();
    PropertyDefinition<?> pd = irelation.getNamingPropertyDefinition();
    if (pd != null) {
      app.println(INFO_DSCFG_CREATE_NAME_PROMPT_NAMING.get(ufn, pd.getName()));
      app.println();
      app.println(pd.getSynopsis(), 4);
      if (pd.getDescription() != null) {
        app.println();
        app.println(pd.getDescription(), 4);
      }
      PropertyDefinitionUsageBuilder b = new PropertyDefinitionUsageBuilder(
          true);
      app.println();
      app.println(INFO_EDITOR_HEADING_SYNTAX.get(b.getUsage(pd)), 4);
      app.println();
      return app.readValidatedInput(INFO_DSCFG_CREATE_NAME_PROMPT_NAMING_CONT
          .get(ufn), validator);
    } else {
      return app.readValidatedInput(INFO_DSCFG_CREATE_NAME_PROMPT.get(ufn),
          validator);
    }
  }
  // Generate the type name - definition mapping table.
  @SuppressWarnings("unchecked")
  private SortedMap<String, ManagedObjectDefinition<? extends C, ? extends S>>
      getSubTypes(AbstractManagedObjectDefinition<C, S> d) {
    SortedMap<String, ManagedObjectDefinition<? extends C, ? extends S>> map;
    map =
      new TreeMap<String, ManagedObjectDefinition<? extends C, ? extends S>>();
    // If the top-level definition is instantiable, we use the value
    // "generic".
    if (d instanceof ManagedObjectDefinition) {
      ManagedObjectDefinition<? extends C, ? extends S> mod =
        (ManagedObjectDefinition<? extends C, ? extends S>) d;
      map.put(GENERIC_TYPE, mod);
    }
    // Process its sub-definitions.
    String suffix = "-" + d.getName();
    for (AbstractManagedObjectDefinition<? extends C, ? extends S> c : d
        .getAllChildren()) {
      if (c instanceof ManagedObjectDefinition) {
        ManagedObjectDefinition<? extends C, ? extends S> mod =
          (ManagedObjectDefinition<? extends C, ? extends S>) c;
        // For the type name we shorten it, if possible, by stripping
        // off the trailing part of the name which matches the
        // base-type.
        String name = mod.getName();
        if (name.endsWith(suffix)) {
          name = name.substring(0, name.length() - suffix.length());
        }
        map.put(name, mod);
      }
    }
    return map;
  }
  // Set a property's initial values.
  private <T> void setProperty(ManagedObject<?> mo,
      MyPropertyProvider provider, PropertyDefinition<T> pd) {
opends/src/server/org/opends/server/tools/dsconfig/PropertyValueEditor.java
@@ -51,6 +51,7 @@
import org.opends.server.admin.ConfigurationClient;
import org.opends.server.admin.DefaultBehaviorProviderVisitor;
import org.opends.server.admin.DefinedDefaultBehaviorProvider;
import org.opends.server.admin.DefinitionDecodingException;
import org.opends.server.admin.EnumPropertyDefinition;
import org.opends.server.admin.IllegalPropertyValueException;
import org.opends.server.admin.IllegalPropertyValueStringException;
@@ -71,7 +72,10 @@
import org.opends.server.admin.client.AuthorizationException;
import org.opends.server.admin.client.CommunicationException;
import org.opends.server.admin.client.ManagedObject;
import org.opends.server.admin.client.ManagedObjectDecodingException;
import org.opends.server.admin.client.ManagementContext;
import org.opends.server.protocols.ldap.LDAPResultCode;
import org.opends.server.tools.ClientException;
import org.opends.server.util.Validator;
import org.opends.server.util.cli.CLIException;
import org.opends.server.util.cli.ConsoleApplication;
@@ -91,6 +95,86 @@
final class PropertyValueEditor {
  /**
   * A menu call-back which can be used to dynamically create new
   * components when configuring aggregation based properties.
   */
  private final class CreateComponentCallback
      <C extends ConfigurationClient, S extends Configuration>
      implements MenuCallback<String> {
    // The aggregation property definition.
    private final AggregationPropertyDefinition<C, S> pd;
    // Creates a new component create call-back for the provided
    // aggregation property definition.
    private CreateComponentCallback(AggregationPropertyDefinition<C, S> pd) {
      this.pd = pd;
    }
    /**
     * {@inheritDoc}
     */
    public MenuResult<String> invoke(ConsoleApplication app)
        throws CLIException {
      try {
        // First get the parent managed object.
        InstantiableRelationDefinition<?, ?> rd = pd.getRelationDefinition();
        ManagedObjectPath<?, ?> path = pd.getParentPath();
        Message ufn = rd.getUserFriendlyName();
        ManagedObject<?> parent;
        try {
          parent = 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 pufn = path.getManagedObjectDefinition()
              .getUserFriendlyName();
          Message msg = ERR_DSCFG_ERROR_GET_PARENT_DDE.get(pufn, pufn, pufn);
          throw new ClientException(LDAPResultCode.OPERATIONS_ERROR, msg);
        } catch (ManagedObjectDecodingException e) {
          Message pufn = path.getManagedObjectDefinition()
              .getUserFriendlyName();
          Message msg = ERR_DSCFG_ERROR_GET_PARENT_MODE.get(pufn);
          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.CLIENT_SIDE_SERVER_DOWN,
              msg);
        } catch (ManagedObjectNotFoundException e) {
          Message pufn = path.getManagedObjectDefinition()
              .getUserFriendlyName();
          Message msg = ERR_DSCFG_ERROR_GET_PARENT_MONFE.get(pufn);
          throw new ClientException(LDAPResultCode.NO_SUCH_OBJECT, msg);
        }
        // Now let the user create the child component.
        app.println();
        app.println();
        return CreateSubCommandHandler.createManagedObject(app, context,
            parent, rd);
      } catch (ClientException e) {
        // FIXME: should really do something better with the exception
        // handling here. For example, if a authz or communications
        // exception occurs then the application should exit.
        app.println();
        app.println(e.getMessageObject());
        app.println();
        app.pressReturnToContinue();
        return MenuResult.cancel();
      }
    }
  }
  /**
   * A help call-back which displays a description and summary of a
   * component and its properties.
   */
@@ -409,11 +493,13 @@
        return MenuResult.quit();
      }
      // FIXME: give the user the option to enable/create a component.
      for (String value : values) {
        Message option = getPropertyValues(d, Collections.singleton(value));
        builder.addNumberedOption(option, MenuResult.success(value));
      }
      MenuCallback<String> callback = new CreateComponentCallback<C, S>(d);
      builder.addNumberedOption(INFO_EDITOR_OPTION_CREATE_A_NEW_COMPONENT
          .get(rd.getUserFriendlyName()), callback);
      builder.addHelpOption(new PropertyHelpCallback(mo
          .getManagedObjectDefinition(), d));
@@ -618,11 +704,10 @@
    public <C extends ConfigurationClient, S extends Configuration>
        MenuResult<Boolean> visitAggregation(
        final AggregationPropertyDefinition<C, S> d, Void p) {
      // FIXME: give the user the option to enable/create a component.
      final SortedSet<String> defaultValues = mo.getPropertyDefaultValues(d);
      final SortedSet<String> oldValues = mo.getPropertyValues(d);
      final SortedSet<String> currentValues = mo.getPropertyValues(d);
      InstantiableRelationDefinition<C, S> rd = d.getRelationDefinition();
      final InstantiableRelationDefinition<C, S> rd = d.getRelationDefinition();
      final Message ufpn = rd.getUserFriendlyPluralName();
      boolean isFirst = true;
@@ -679,6 +764,11 @@
                    .singleton(value));
                builder.addNumberedOption(svalue, MenuResult.success(value));
              }
              MenuCallback<String> callback = new CreateComponentCallback<C, S>(
                  d);
              builder.addNumberedOption(
                  INFO_EDITOR_OPTION_CREATE_A_NEW_COMPONENT.get(rd
                      .getUserFriendlyName()), callback);
              if (values.size() > 1) {
                // No point in having this option if there's only one
@@ -1550,6 +1640,9 @@
        builder.addNumberedOption(option, MenuResult.success(value));
      }
      MenuCallback<String> callback = new CreateComponentCallback<C, S>(d);
      builder.addNumberedOption(INFO_EDITOR_OPTION_CREATE_A_NEW_COMPONENT
          .get(ufn), callback);
      // Third option is to reset the value back to its default.
      if (mo.isPropertyPresent(d) && !query.isDefined()) {
@@ -1559,8 +1652,6 @@
        }
      }
      // FIXME: give the user the option to enable/create a component.
      return runMenu(d, builder);
    }