0

I would like to provide a search string for my program like:

cmd.execute("getDevices", "-h 1.2.3.4", "-p myPSW", "-u myUser", "-n red|blue&black,-nonprod");

I want to create predicates to search for hostNames that contain red OR blue AND Black, but NOT nonprod. It is unclear to me how to go about parsing this the logical operators along with the Strings in Picocli to create a Predicate. Is there a simple and Straight forward way to parse a String to a predicate?

My CLI is set up as follows:

@Command(name = "HostMagicCLI", mixinStandardHelpOptions = true,
        version = "1.0",
        description = "Do Stuff With Hosts"
        ,
        subcommands = {TufinDevices.class}
)

public class HostMagicCLI implements Runnable {

    public static void main(String[] args) {
        CommandLine cmd = new CommandLine(new InterfaceMagicCLI());
        cmd.setExecutionStrategy(new RunAll());
        cmd.getHelpSectionMap().put(SECTION_KEY_COMMAND_LIST, new MyCommandListRenderer());
        cmd.usage(System.out);
        cmd.execute("getDevices", "-h1.2.3.4", "-p myPSW", "-u myUser", "-n red|blue&black");

    }

    @Override
    public void run() {
        System.out.println("Running..");
    }
     }

@Command(name = "getDevices", aliases = {"l"}, description = "SpecifyTufin Credentials", subcommands = {InterfaceCommand.class})

class TufinDevices implements Runnable {
 .
 .//Options to collect user,psw, host etc.
 .
@CommandLine.Option(names = {"-n", "--n"}, split = ",", arity = "0..*", description = "Hostname Contains")
String[] hostNameContains;
private void filter(TufinDeviceCollection<TufinDevice> devices) {
    if (hostNameContains != null) {
        Predicate< ? super TufinDevice> deviceFilter = device -> Arrays.stream(hostNameContains)
                .allMatch(input -> device.getHostName().toLowerCase().contains(input.toLowerCase()));

        devices = devices.stream()
                .sequential()
                .filter(deviceFilter)
                .collect(Collectors.toCollection(TufinDeviceCollection<TufinDevice>::new));
    }
@Override
public void run() {
    try {
        TufinDeviceCollection<TufinDevice> FETCH_DEVICES = Tufin.FETCH_DEVICES(user.trim(), password.trim(), hostName.trim());
        this.filter(FETCH_DEVICES);
    } catch (IOException | NoSuchAlgorithmException | KeyManagementException | IPConverter.InvalidIPException ex) {
        Logger.getLogger(TufinDevices.class.getName()).log(Level.SEVERE, null, ex);
    }

}

}

CoupFlu
  • 311
  • 4
  • 20

1 Answers1

0

I suspect you may want to use a library for parsing the string that the end user specifies as the filter expression (the -n parameter). It may be an idea to look at libraries like Spring Expression Language, OGNL, JXPath, there may be others. Alternatively, if it is easy to write such a filter in Groovy or BeanShell, these languages can be called from Java, so you can call that filter from the Java command.


CAUTION: I notice the example passes parameter to the picocli parser like this:

cmd.execute("getDevices", "-h 1.2.3.4", "-p myPSW", "-u myUser", "-n red|blue&black,-nonprod");

This will probably give an error explaining that "there is no -p myPSW option defined".

In your testing, if you call the execute method directly, make sure to pass parameters separately like this:

cmd.execute("getDevices", "-h", "1.2.3.4", "-p", "myPSW", "-u", "myUser", "-n", "red|blue&black,-nonprod");
Remko Popma
  • 35,130
  • 11
  • 92
  • 114