/**
  * Adds a node path which is required to exist before the command can be used.
  *
  * @param requiredPath node path which is required to exist before the command can be used.
  */
 protected void addRequiredPath(String requiredPath) {
   if (requiredPath == null) {
     throw new IllegalArgumentException("Required path can't be null.");
   }
   DefaultOperationRequestAddress requiredAddress = new DefaultOperationRequestAddress();
   CommandLineParser.CallbackHandler handler = new DefaultCallbackHandler(requiredAddress);
   try {
     ParserUtil.parseOperationRequest(requiredPath, handler);
   } catch (CommandFormatException e) {
     throw new IllegalArgumentException("Failed to parse nodeType: " + e.getMessage());
   }
   addRequiredPath(requiredAddress);
 }
  public GenericTypeOperationHandler(
      String nodeType, String idProperty, List<String> excludeOperations) {

    super("generic-type-operation", true);

    if (nodeType == null) {
      throw new IllegalArgumentException("Node type is null.");
    }
    this.nodeType = nodeType;

    helpArg =
        new ArgumentWithoutValue(this, "--help", "-h") {
          @Override
          public boolean canAppearNext(CommandContext ctx) throws CommandFormatException {
            if (ctx.isDomainMode() && !profile.isValueComplete(ctx.getParsedCommandLine())) {
              return false;
            }
            return super.canAppearNext(ctx);
          }
        };

    nodePath = new DefaultOperationRequestAddress();
    CommandLineParser.CallbackHandler handler = new DefaultCallbackHandler(nodePath);
    try {
      ParserUtil.parseOperationRequest(nodeType, handler);
    } catch (CommandFormatException e) {
      throw new IllegalArgumentException("Failed to parse nodeType: " + e.getMessage());
    }

    if (!nodePath.endsOnType()) {
      throw new IllegalArgumentException("The node path doesn't end on a type: '" + nodeType + "'");
    }
    this.type = nodePath.getNodeType();
    nodePath.toParentNode();
    addRequiredPath(nodePath);
    this.commandName = type;
    this.idProperty = idProperty;

    this.excludeOps = excludeOperations;

    profile =
        new ArgumentWithValue(
            this,
            new DefaultCompleter(
                new CandidatesProvider() {
                  @Override
                  public List<String> getAllCandidates(CommandContext ctx) {
                    return Util.getNodeNames(ctx.getModelControllerClient(), null, "profile");
                  }
                }),
            "--profile") {
          @Override
          public boolean canAppearNext(CommandContext ctx) throws CommandFormatException {
            if (!ctx.isDomainMode()) {
              return false;
            }
            return super.canAppearNext(ctx);
          }
        };
    // profile.addCantAppearAfter(helpArg);

    operation =
        new ArgumentWithValue(
            this,
            new DefaultCompleter(
                new CandidatesProvider() {
                  @Override
                  public Collection<String> getAllCandidates(CommandContext ctx) {
                    DefaultOperationRequestAddress address = new DefaultOperationRequestAddress();
                    if (ctx.isDomainMode()) {
                      final String profileName = profile.getValue(ctx.getParsedCommandLine());
                      if (profileName == null) {
                        return Collections.emptyList();
                      }
                      address.toNode("profile", profileName);
                    }

                    for (OperationRequestAddress.Node node : nodePath) {
                      address.toNode(node.getType(), node.getName());
                    }
                    address.toNode(type, "?");
                    Collection<String> ops =
                        ctx.getOperationCandidatesProvider().getOperationNames(ctx, address);
                    ops.removeAll(excludeOps);
                    return ops;
                  }
                }),
            0,
            "--operation") {
          @Override
          public boolean canAppearNext(CommandContext ctx) throws CommandFormatException {
            if (ctx.isDomainMode() && !profile.isValueComplete(ctx.getParsedCommandLine())) {
              return false;
            }
            return super.canAppearNext(ctx);
          }
        };
    operation.addCantAppearAfter(helpArg);

    name =
        new ArgumentWithValue(
            this,
            new DefaultCompleter(
                new DefaultCompleter.CandidatesProvider() {
                  @Override
                  public List<String> getAllCandidates(CommandContext ctx) {
                    ModelControllerClient client = ctx.getModelControllerClient();
                    if (client == null) {
                      return Collections.emptyList();
                    }

                    DefaultOperationRequestAddress address = new DefaultOperationRequestAddress();
                    if (ctx.isDomainMode()) {
                      final String profileName = profile.getValue(ctx.getParsedCommandLine());
                      if (profile == null) {
                        return Collections.emptyList();
                      }
                      address.toNode("profile", profileName);
                    }

                    for (OperationRequestAddress.Node node : nodePath) {
                      address.toNode(node.getType(), node.getName());
                    }

                    return Util.getNodeNames(ctx.getModelControllerClient(), address, type);
                  }
                }),
            (idProperty == null ? "--name" : "--" + idProperty)) {
          @Override
          public boolean canAppearNext(CommandContext ctx) throws CommandFormatException {
            if (ctx.isDomainMode() && !profile.isValueComplete(ctx.getParsedCommandLine())) {
              return false;
            }
            return super.canAppearNext(ctx);
          }
        };
    name.addCantAppearAfter(helpArg);

    helpArg.addCantAppearAfter(name);

    helpProperties = new ArgumentWithoutValue(this, "--properties");
    helpProperties.addRequiredPreceding(helpArg);
    helpProperties.addCantAppearAfter(operation);

    helpCommands = new ArgumentWithoutValue(this, "--commands");
    helpCommands.addRequiredPreceding(helpArg);
    helpCommands.addCantAppearAfter(operation);
    helpCommands.addCantAppearAfter(helpProperties);
    helpProperties.addCantAppearAfter(helpCommands);

    ///
    staticArgs.add(helpArg);
    staticArgs.add(helpCommands);
    staticArgs.add(helpProperties);
    staticArgs.add(profile);
    staticArgs.add(name);
    staticArgs.add(operation);
  }