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

matthew_swift
06.44.2007 0f27e95935087142ed026374603adb3746d9b67b
Fix issue 1826: delete of missing managed objects should throw error in dsconfig

This change fixes a bug in the admin framework where an attempt to delete a non-existent managed object would not throw a ManagedObjectNotFoundException. In addition, a "-f" (or "--force") option has been added to the dsconfig delete-xxx sub-command to simulate the "-f" usage supported in the Unix "rm" command. If the "-f" option is specified, then no error will be returned to the client if the named managed object or its parents do not exist.
4 files modified
177 ■■■■■ changed files
opends/src/server/org/opends/server/admin/client/ldap/LDAPManagedObject.java 4 ●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/messages/ToolMessages.java 13 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/dsconfig/CLIProfile.java 19 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/dsconfig/DeleteSubCommandHandler.java 141 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/admin/client/ldap/LDAPManagedObject.java
@@ -1058,7 +1058,7 @@
  // Remove the named managed object.
  private void removeManagedObject(ManagedObjectPath p)
      throws CommunicationException, AuthorizationException,
      OperationRejectedException {
      OperationRejectedException, ManagedObjectNotFoundException {
    LdapName dn = LDAPNameBuilder.create(p, context.getLDAPProfile());
    if (entryExists(dn)) {
      // Delete the entry and any subordinate entries.
@@ -1070,6 +1070,8 @@
      } catch (NamingException e) {
        adaptNamingException(e);
      }
    } else {
      throw new ManagedObjectNotFoundException();
    }
  }
opends/src/server/org/opends/server/messages/ToolMessages.java
@@ -8990,6 +8990,17 @@
  /**
   * The message ID for the message that will be used as the
   * description of the delete-xxx force argument. This takes a single
   * argument which is the user-friendly plural name of the type of
   * managed objects which can be deleted.
   */
  public static final int MSGID_DSCFG_DESCRIPTION_FORCE =
       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1196;
  /**
   * Associates a set of generic messages with the message IDs defined in this
   * class.
   */
@@ -11331,6 +11342,8 @@
                    "Modifies the display output to show one property " +
                    "value per line");
    registerMessage(MSGID_DSCFG_DESCRIPTION_FORCE, "Ignore non-existent %s");
    registerMessage(MSGID_DSCFG_DESCRIPTION_UNIT_TIME,
                    "Display time data using the specified unit. The value " +
                    "for UNIT can be one of ms, s, m, h, d, or w " +
opends/src/server/org/opends/server/tools/dsconfig/CLIProfile.java
@@ -33,7 +33,6 @@
import java.util.LinkedHashSet;
import java.util.Set;
import org.opends.server.admin.InstantiableRelationDefinition;
import org.opends.server.admin.ManagedObjectDefinitionResource;
import org.opends.server.admin.RelationDefinition;
@@ -84,22 +83,4 @@
        + r.getName() + ".list-properties");
    return new LinkedHashSet<String>(Arrays.asList(s.split(",")));
  }
  /**
   * Gets the command line operand name which should be used to
   * identify the names of managed objects associated with an
   * instantiable relation.
   *
   * @param r
   *          The instantiable relation definition.
   * @return Returns the command line operand name which should be
   *         used to identify the names of managed objects associated
   *         with an instantiable relation.
   */
  public String getOperandName(InstantiableRelationDefinition<?, ?> r) {
    return resource.getString(r.getParentDefinition(), "relation."
        + r.getName() + ".operand-name");
  }
}
opends/src/server/org/opends/server/tools/dsconfig/DeleteSubCommandHandler.java
@@ -50,6 +50,7 @@
import org.opends.server.protocols.ldap.LDAPResultCode;
import org.opends.server.tools.ClientException;
import org.opends.server.util.args.ArgumentException;
import org.opends.server.util.args.BooleanArgument;
import org.opends.server.util.args.StringArgument;
import org.opends.server.util.args.SubCommand;
import org.opends.server.util.args.SubCommandArgumentParser;
@@ -65,6 +66,18 @@
final class DeleteSubCommandHandler extends SubCommandHandler {
  /**
   * The value for the long option force.
   */
  private static final String OPTION_DSCFG_LONG_FORCE = "force";
  /**
   * The value for the short option force.
   */
  private static final char OPTION_DSCFG_SHORT_FORCE = 'f';
  /**
   * Creates a new delete-xxx sub-command for an instantiable
   * relation.
   *
@@ -105,6 +118,9 @@
    return new DeleteSubCommandHandler(parser, p, r, p.child(r));
  }
  // The argument which should be used to force deletion.
  private final BooleanArgument forceArgument;
  // The sub-commands naming arguments.
  private final List<StringArgument> namingArgs;
@@ -129,13 +145,20 @@
    // Create the sub-command.
    String name = "delete-" + r.getName();
    String ufpn = r.getChildDefinition().getUserFriendlyPluralName();
    int descriptionID = MSGID_DSCFG_DESCRIPTION_SUBCMD_DELETE;
    this.subCommand = new SubCommand(parser, name, false, 0, 0, null,
        descriptionID, r.getChildDefinition().getUserFriendlyPluralName());
        descriptionID, ufpn);
    // Create the naming arguments.
    this.namingArgs = createNamingArgs(subCommand, c);
    // Create the --force argument which is used to force deletion.
    this.forceArgument = new BooleanArgument(OPTION_DSCFG_LONG_FORCE,
        OPTION_DSCFG_SHORT_FORCE, OPTION_DSCFG_LONG_FORCE,
        MSGID_DSCFG_DESCRIPTION_FORCE, ufpn);
    subCommand.addArgument(forceArgument);
    // Register the tags associated with the child managed objects.
    addTags(relation.getChildDefinition().getAllTags());
  }
@@ -163,7 +186,7 @@
    // Delete the child managed object.
    ManagementContext context = app.getManagementContext();
    ManagedObject<?> parent;
    ManagedObject<?> parent = null;
    try {
      parent = getManagedObject(context, path, names.subList(0,
          names.size() - 1));
@@ -194,66 +217,74 @@
      throw new ClientException(LDAPResultCode.CONSTRAINT_VIOLATION, msgID,
          msg);
    } catch (ManagedObjectNotFoundException e) {
      int msgID = MSGID_DSCFG_ERROR_GET_PARENT_MONFE;
      String ufn = path.getManagedObjectDefinition().getUserFriendlyName();
      String msg = getMessage(msgID, ufn);
      throw new ClientException(LDAPResultCode.NO_SUCH_OBJECT, msgID, msg);
      // Ignore the error if the deletion is being forced.
      if (!forceArgument.isPresent()) {
        int msgID = MSGID_DSCFG_ERROR_GET_PARENT_MONFE;
        String ufn = path.getManagedObjectDefinition().getUserFriendlyName();
        String msg = getMessage(msgID, ufn);
        throw new ClientException(LDAPResultCode.NO_SUCH_OBJECT, msgID, msg);
      }
    }
    try {
      // Confirm deletion.
      String prompt = String.format(Messages.getString("delete.confirm"),
          relation.getUserFriendlyName());
      if (!app.confirmAction(prompt)) {
        // Output failure message.
        String msg = String.format(Messages.getString("delete.failed"),
    if (parent != null) {
      try {
        // Confirm deletion.
        String prompt = String.format(Messages.getString("delete.confirm"),
            relation.getUserFriendlyName());
        app.displayVerboseMessage(msg);
        return 1;
      }
        if (!app.confirmAction(prompt)) {
          // Output failure message.
          String msg = String.format(Messages.getString("delete.failed"),
              relation.getUserFriendlyName());
          app.displayVerboseMessage(msg);
          return 1;
        }
      if (relation instanceof InstantiableRelationDefinition) {
        InstantiableRelationDefinition<?, ?> irelation =
          (InstantiableRelationDefinition<?, ?>) relation;
        parent.removeChild(irelation, names.get(names.size() - 1));
      } else if (relation instanceof OptionalRelationDefinition) {
        OptionalRelationDefinition<?, ?> orelation =
          (OptionalRelationDefinition<?, ?>) relation;
        parent.removeChild(orelation);
        if (relation instanceof InstantiableRelationDefinition) {
          InstantiableRelationDefinition<?, ?> irelation =
            (InstantiableRelationDefinition<?, ?>) relation;
          parent.removeChild(irelation, names.get(names.size() - 1));
        } else if (relation instanceof OptionalRelationDefinition) {
          OptionalRelationDefinition<?, ?> orelation =
            (OptionalRelationDefinition<?, ?>) relation;
          parent.removeChild(orelation);
        }
      } catch (AuthorizationException e) {
        int msgID = MSGID_DSCFG_ERROR_DELETE_AUTHZ;
        String msg = getMessage(msgID, relation.getUserFriendlyName());
        throw new ClientException(LDAPResultCode.INSUFFICIENT_ACCESS_RIGHTS,
            msgID, msg);
      } catch (OperationRejectedException e) {
        int msgID = MSGID_DSCFG_ERROR_DELETE_ORE;
        String msg = getMessage(msgID, relation.getUserFriendlyName(), e
            .getMessage());
        throw new ClientException(LDAPResultCode.CONSTRAINT_VIOLATION, msgID,
            msg);
      } catch (ManagedObjectNotFoundException e) {
        // Ignore the error if the deletion is being forced.
        if (!forceArgument.isPresent()) {
          int msgID = MSGID_DSCFG_ERROR_DELETE_MONFE;
          String msg = getMessage(msgID, relation.getUserFriendlyName());
          throw new ClientException(LDAPResultCode.NO_SUCH_OBJECT, msgID, msg);
        }
      } catch (ConcurrentModificationException e) {
        int msgID = MSGID_DSCFG_ERROR_DELETE_CME;
        String msg = getMessage(msgID, relation.getUserFriendlyName());
        throw new ClientException(LDAPResultCode.CONSTRAINT_VIOLATION, msgID,
            msg);
      } catch (CommunicationException e) {
        int msgID = MSGID_DSCFG_ERROR_DELETE_CE;
        String msg = getMessage(msgID, relation.getUserFriendlyName(), e
            .getMessage());
        throw new ClientException(LDAPResultCode.CLIENT_SIDE_SERVER_DOWN,
            msgID, msg);
      }
      // Output success message.
      String msg = String.format(Messages.getString("delete.done"),
          relation.getUserFriendlyName());
      app.displayVerboseMessage(msg);
    } catch (AuthorizationException e) {
      int msgID = MSGID_DSCFG_ERROR_DELETE_AUTHZ;
      String msg = getMessage(msgID, relation.getUserFriendlyName());
      throw new ClientException(LDAPResultCode.INSUFFICIENT_ACCESS_RIGHTS,
          msgID, msg);
    } catch (OperationRejectedException e) {
      int msgID = MSGID_DSCFG_ERROR_DELETE_ORE;
      String msg = getMessage(msgID, relation.getUserFriendlyName(), e
          .getMessage());
      throw new ClientException(LDAPResultCode.CONSTRAINT_VIOLATION, msgID,
          msg);
    } catch (ManagedObjectNotFoundException e) {
      int msgID = MSGID_DSCFG_ERROR_DELETE_MONFE;
      String msg = getMessage(msgID, relation.getUserFriendlyName());
      throw new ClientException(LDAPResultCode.NO_SUCH_OBJECT, msgID, msg);
    } catch (ConcurrentModificationException e) {
      int msgID = MSGID_DSCFG_ERROR_DELETE_CME;
      String msg = getMessage(msgID, relation.getUserFriendlyName());
      throw new ClientException(LDAPResultCode.CONSTRAINT_VIOLATION, msgID,
          msg);
    } catch (CommunicationException e) {
      int msgID = MSGID_DSCFG_ERROR_DELETE_CE;
      String msg = getMessage(msgID, relation.getUserFriendlyName(), e
          .getMessage());
      throw new ClientException(LDAPResultCode.CLIENT_SIDE_SERVER_DOWN, msgID,
          msg);
    }
    // Output success message.
    String msg = String.format(Messages.getString("delete.done"), relation
        .getUserFriendlyName());
    app.displayVerboseMessage(msg);
    return 0;
  }