ShortErrorMessageHandler   A
last analyzed

Complexity

Total Complexity 2

Size/Duplication

Total Lines 16
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
eloc 12
dl 0
loc 16
ccs 0
cts 8
cp 0
rs 10
c 0
b 0
f 0
wmc 2

1 Method

Rating   Name   Duplication   Size   Complexity  
A handleParseException(ParameterException,String[]) 0 14 2
1
/*
2
 * Copyright 2014-2018, Armenak Grigoryan, and individual contributors as indicated
3
 * by the @authors tag. See the copyright.txt in the distribution for a
4
 * full listing of individual contributors.
5
 *
6
 * This is free software; you can redistribute it and/or modify it
7
 * under the terms of the GNU Lesser General Public License as
8
 * published by the Free Software Foundation; either version 2.1 of
9
 * the License, or (at your option) any later version.
10
 *
11
 * This software is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
 * Lesser General Public License for more details.
15
 */
16
package com.strider.datadefender;
17
18
import com.strider.datadefender.discoverer.Discoverer;
19
import com.strider.datadefender.requirement.Requirement;
20
import com.strider.datadefender.requirement.file.Loader;
21
22
import java.io.FileNotFoundException;
23
import java.io.PrintWriter;
24
import java.lang.reflect.InvocationTargetException;
25
import java.util.concurrent.Callable;
26
import java.util.stream.Collectors;
27
import javax.xml.bind.JAXBException;
28
29
import org.apache.commons.lang3.StringUtils;
30
import org.apache.logging.log4j.ThreadContext;
31
32
import picocli.CommandLine;
33
import picocli.CommandLine.Command;
34
import picocli.CommandLine.HelpCommand;
35
import picocli.CommandLine.IParameterExceptionHandler;
36
import picocli.CommandLine.Model.CommandSpec;
37
import picocli.CommandLine.ParameterException;
38
import picocli.CommandLine.ScopeType;
39
import picocli.CommandLine.TypeConversionException;
40
import picocli.CommandLine.UnmatchedArgumentException;
41
42
import lombok.extern.log4j.Log4j2;
43
import org.xml.sax.SAXException;
44
45
/**
46
 * Entry point to Data Defender.
47
 *
48
 * This class will parse and analyze the parameters and execute appropriate
49
 * service.
50
 *
51
 * @author Zaahid Bateson
52
 */
53
@Command(
54
    name = "datadefender",
55
    mixinStandardHelpOptions = true,
56
    version = "2.0.1",
57
    description = "Data detection and anonymization tool",
58
    synopsisSubcommandLabel = "COMMAND",
59
    subcommands = {
60
        HelpCommand.class,
61
        Anonymize.class,
62
        Extract.class,
63
        Discover.class
64
    }
65
)
66
@Log4j2
67
public class DataDefender implements Callable<Integer> {
68
69
    // initializing system property used by ModelDiscoveryConfig option parameter help
70
    static {
71
        System.setProperty("AVAILABLE-MODELS", StringUtils.join(
72
            Discoverer.BUILT_IN_MODELS.keySet().stream().sorted().collect(Collectors.toList()),
73
            ", "
74
        ));
75
    }
76
77
    @CommandLine.Option(names = "--debug", description = "Enable debug logging in log file", scope = ScopeType.INHERIT)
78
    public void setDebug(boolean debug) {
79
        System.out.println("DEBUG file logging turned on.");
80
        ThreadContext.put("file-level", "debug");
81
        log.warn("Private/sensitive data that should be anonymized will be "
82
            + "logged to configured debug output streams.");
83
    }
84
85
    @CommandLine.Option(names = { "-v", "--verbose" }, description = "Enable more verbose console output, specify two -v for console debug logging", scope = ScopeType.INHERIT)
86
    public void setVerbose(boolean[] verbosity) {
87
        if (verbosity.length < 2) {
88
            ThreadContext.put("console-level", "info");
89
        } else {
90
            ThreadContext.put("console-level", "debug");
91
            log.warn("Private/sensitive data that should be anonymized will be "
92
                + "logged to the console in this mode.");
93
        }
94
    }
95
96
    /**
97
     * Copied from picocli documentation, presents a shorter "Usage" help when
98
     * there's an error in the options/arguments.
99
     *
100
     * https://picocli.info
101
     */
102
    public static class ShortErrorMessageHandler implements IParameterExceptionHandler {
103
104
        public int handleParseException(ParameterException ex, String[] args) {
105
            CommandLine cmd = ex.getCommandLine();
106
            PrintWriter writer = cmd.getErr();
107
108
            writer.println(ex.getMessage());
109
            UnmatchedArgumentException.printSuggestions(ex, writer);
110
            writer.print(cmd.getHelp().fullSynopsis()); // since 4.1
111
112
            CommandSpec spec = cmd.getCommandSpec();
113
            writer.printf("Try '%s --help' for more information.%n", spec.qualifiedName());
114
115
            return cmd.getExitCodeExceptionMapper() != null
116
                        ? cmd.getExitCodeExceptionMapper().getExitCode(ex)
117
                        : spec.exitCodeOnInvalidInput();
118
        }
119
    }
120
121
    public static class RequirementConverter implements CommandLine.ITypeConverter<Requirement> {
122
        public Requirement convert(String value) throws Exception {
123
            Loader loader = new Loader();
124
            try {
125
                return loader.load(value);
126
            } catch (FileNotFoundException e) {
127
                log.debug("Error loading requirements file", e);
128
                throw new TypeConversionException("Unable to load requirements file: " + e.getMessage());
129
            } catch (IllegalAccessException | IllegalArgumentException | InstantiationException | NoSuchMethodException | InvocationTargetException | JAXBException | SAXException e) {
130
                Throwable exc = e;
131
                if (StringUtils.isBlank(e.getMessage()) && e.getCause() != null) {
132
                    exc = e.getCause();
133
                }
134
                log.debug("Error loading requirements.", exc);
135
                throw new TypeConversionException("Unable to load requirements file: " + exc.getMessage());
136
            }
137
        }
138
    }
139
140
    @Override
141
    public Integer call() throws Exception {
142
        CommandLine.usage(this, System.out);
143
        return 0;
144
    }
145
146
    public static void main(String... args) throws Exception {
147
148
        ThreadContext.put("console-level", "");
149
        ThreadContext.put("file-level", "");
150
151
        CommandLine cmd = new CommandLine(new DataDefender())
152
            .registerConverter(Requirement.class, new RequirementConverter())
153
            .setParameterExceptionHandler(new ShortErrorMessageHandler());
154
        int exitCode = cmd.execute(args);
155
        System.exit(exitCode);
156
    }
157
}
158