Skip to content

Commit

Permalink
Merge branch '14-change-log-level-settings-at-cli' into 'master'
Browse files Browse the repository at this point in the history
WIP: Resolve "Change log level settings at CLI"

Closes #14

See merge request kosit/xml-mutate!54
  • Loading branch information
rkottmann committed Jun 20, 2022
2 parents 815e355 + 96919d2 commit 27232b6
Show file tree
Hide file tree
Showing 4 changed files with 142 additions and 37 deletions.
7 changes: 7 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,13 @@
<artifactId>log4j-slf4j-impl</artifactId>
<version>${log4j.version}</version>
</dependency>

<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>${log4j.version}</version>
</dependency>

<dependency>
<groupId>net.sf.saxon</groupId>
<artifactId>Saxon-HE</artifactId>
Expand Down
116 changes: 82 additions & 34 deletions src/main/java/de/kosit/xmlmutate/cli/XmlMutate.java
Original file line number Diff line number Diff line change
@@ -1,82 +1,112 @@
// Generated by delombok at Fri Aug 13 16:07:39 CEST 2021
package de.kosit.xmlmutate.cli;

import de.kosit.xmlmutate.mutation.NamedTemplate;
import de.kosit.xmlmutate.mutation.Schematron;
import de.kosit.xmlmutate.runner.*;
import de.kosit.xmlmutate.schematron.SchematronCompiler;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.ConfigurationSource;
import org.apache.logging.log4j.core.config.Configurator;
import org.apache.logging.log4j.core.config.xml.XmlConfigurationFactory;
import org.fusesource.jansi.AnsiConsole;
import picocli.CommandLine;
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;
import picocli.CommandLine.Parameters;
import picocli.CommandLine.ParseResult;

import javax.xml.validation.Schema;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.nio.file.Files;
import java.nio.file.Path;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import javax.xml.validation.Schema;

import org.fusesource.jansi.AnsiConsole;

import de.kosit.xmlmutate.mutation.NamedTemplate;
import de.kosit.xmlmutate.mutation.Schematron;
import de.kosit.xmlmutate.runner.FailureMode;
import de.kosit.xmlmutate.runner.MutationRunner;
import de.kosit.xmlmutate.runner.RunMode;
import de.kosit.xmlmutate.runner.RunnerConfig;
import de.kosit.xmlmutate.runner.RunnerResult;
import de.kosit.xmlmutate.runner.SavingMode;
import de.kosit.xmlmutate.runner.Services;
import de.kosit.xmlmutate.schematron.SchematronCompiler;
import picocli.CommandLine;
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;
import picocli.CommandLine.Parameters;
import picocli.CommandLine.ParseResult;

/**
* Base class for command line interface.
*
* @author Andreas Penski
* @author Renzo Kottmann
*/
@Command(description = "XMl-MutaTE: XML Mutation and Test Management tool.", name = "XML Mutate", mixinStandardHelpOptions = true, separator = " ")
@Command(description = "XMl-MutaTE: XML Mutation and Test Management tool.", name = "XML Mutate", mixinStandardHelpOptions = true,
separator = " ")
@Slf4j
public class XmlMutate implements Callable<Integer> {
private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(XmlMutate.class);

@Option(names = {"-o", "--target"}, description = "The target folder, where artifacts are generated.", defaultValue = "target")
private Path target;

@Option(names = {"-x", "--schema", "--xsd"}, paramLabel = "*.xsd", description = "The XML Schema file for validation")
private Path schemaLocation;

@Option(names = {"-s", "--schematron"}, paramLabel = "MAP", description = "Compiled schematron file(s) for validation")
private final Map<String, Path> schematrons = new HashMap<>();
private final Map<String, Path> schematrons = new HashMap<String, Path>();

@Option(names = {"-m", "--mode"}, paramLabel = "MODE", description = "The actual processing mode", defaultValue = "ALL")
private RunMode mode;
@Option(names = {"-t", "--transformations"}, paramLabel = "MAP", description = "Named transformations used for the Transformation-Mutator")
private final Map<String, Path> transformations = new HashMap<>();

@Option(names = {"-t", "--transformations"}, paramLabel = "MAP",
description = "Named transformations used for the Transformation-Mutator")
private final Map<String, Path> transformations = new HashMap<String, Path>();

@Option(names = {"-ff", "--fail-fast"}, description = "The run failure control mode for fail fast")
private boolean failfast;

@Option(names = {"-fae", "--fail-at-end"}, description = "The run failure control mode for fail at end")
private boolean failatend;

@Option(names = {"-fn", "--fail-never"}, description = "The run failure control mode for fail never")
private boolean failnever;
@Option(names = {"-isi", "--ignore-schema-invalidity"}, description = "If set, whenever an original document is not schema valid, it wont stop the programm")

@Option(names = {"-isi", "--ignore-schema-invalidity"},
description = "If set, whenever an original document is not schema valid, it wont stop the programm")
private boolean ignoreSchemaInvalidity;
@Option(names = {"--saveParsing"}, description = "Enables the save parsing mode, which does not providing line number information, but is more robust", defaultValue = "false")

@Option(names = {"--saveParsing"},
description = "Enables the save parsing mode, which does not providing line number information, but is more robust",
defaultValue = "false")
private boolean saveParsingMode;
@Option(names = {"-sm", "--saving-mode"}, paramLabel = "SAVING_MODE", description = "How result mutations are saved into the target directory", defaultValue = "SINGLE")
private SavingMode savingMode;

@Option(names = {"-l", "--log"}, paramLabel = "LOGLEVEL", description = "The actual log level", defaultValue = "WARN", converter = LogLevelConverter.class)
private LogLevel logLevel;

@Option(names = {"-lf", "--logfile"}, paramLabel = "LOGFILE", description = "An input configuration log file")
private Path logInputFile;

@Parameters(arity = "1..*", description = "Documents to mutate")
private List<Path> documents;

static class LogLevelConverter implements CommandLine.ITypeConverter<LogLevel> {
@Override
public LogLevel convert(final String value) {
try {
return LogLevel.valueOf(value.toUpperCase());
} catch (final IllegalArgumentException e) {
throw new MutationException(ErrorCode.LOGLEVEL_WRONG, value);
}
}
}

public static void main(final String[] args) {

AnsiConsole.systemInstall();
int i = -1;
try {
final CommandLine commandLine = new CommandLine(new XmlMutate());
commandLine.setExecutionExceptionHandler(XmlMutate::logExecutionException);
commandLine.registerConverter(LogLevel.class, new LogLevelConverter());
i = commandLine.execute(args);
} catch (final Exception e) {
System.err.print(e.getMessage());
Expand All @@ -93,13 +123,31 @@ public static void main(final String[] args) {
*/
@Override
public Integer call() throws Exception {
configureLogging();
final ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
final MutationRunner runner = new MutationRunner(prepareConfig(), executor);
final RunnerResult result = runner.run();
executor.shutdown();
return result.isErrorPresent() ? 1 : 0;
}

private void configureLogging() {
if (logInputFile != null) {
try {
final LoggerContext loggerContext = LoggerContext.getContext(false);
final InputStream inputStream = new FileInputStream(logInputFile.toFile());
final ConfigurationSource source = new ConfigurationSource(inputStream);
final XmlConfigurationFactory xmlConfigurationFactory = new XmlConfigurationFactory();
final Configuration newConfiguration = xmlConfigurationFactory.getConfiguration(loggerContext, source);
loggerContext.setConfiguration(newConfiguration);
} catch (final IOException ex) {
log.error(ex.getMessage(), ex);
}
} else {
Configurator.setAllLevels(LogManager.getRootLogger().getName(), this.logLevel.level);
}
}

/**
* Prepares a {@link RunnerConfig configuration} for the {@link MutationRunner}.
*/
Expand Down
31 changes: 28 additions & 3 deletions src/main/java/de/kosit/xmlmutate/runner/ErrorCode.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,43 @@
package de.kosit.xmlmutate.runner;

import de.init.kosit.commons.util.NamedError;
import org.apache.logging.log4j.Level;

/**
* @author Andreas Penski
*/
public enum ErrorCode implements NamedError {
RESET_NULL("Error resetting node to original state: parent or target is null"), WRONG_OWNER("Target Node is not in the correct document. Can not reset original state"), WRONG_PARENT("There is structural error. Parents are not the same, but this is expected"), INVALID_MUTATION_PRODUCED("Invalid xml mutation produced"), MUTATION_XML_FILE_READ_PROBLEM("Error while while trying to read the xml mutation file"), SCHEMATRON_RULE_NOT_EXIST("Rule {0} does not exist in schematron {1}"), SCHEMATRON_RULE_FAILED_EXPECTATION("Failed expectation"), SCHEMATRON_RULE_FAILED_EXPECTATION_ENTERITY("Failed expectation"), ACTION_RUNNER_ERROR("Error running action {0} in mutation {1} "), ID_ALREADY_DECLARED("Mutation instruction id was already declared"), SCHEMATRON_EVALUATION_ERROR("Schematron evaluation error: {0}"), ORIGINAL_XML_NOT_SCHEMA_VALID("Original document {0} is not schema valid:{1}"), CLI_ARGUMENT_NOT_PRESENT_BUT_PI_EXPECTATION("No {0} given at CLI but expectation declared in a xmute pi");
private final String template;

RESET_NULL("Error resetting node to original state: parent or target is null"),

WRONG_OWNER("Target Node is not in the correct document. Can not reset original state"),

WRONG_PARENT("There is structural error. Parents are not the same, but this is expected"),

INVALID_MUTATION_PRODUCED("Invalid xml mutation produced"),

MUTATION_XML_FILE_READ_PROBLEM("Error while while trying to read the xml mutation file"),

SCHEMATRON_RULE_NOT_EXIST("Rule {0} does not exist in schematron {1}"),

SCHEMATRON_RULE_FAILED_EXPECTATION("Failed expectation assert for {0}"),

ACTION_RUNNER_ERROR("Error running action {0} in mutation {1} "),

ID_ALREADY_DECLARED("Mutation instruction id was already declared"),

SCHEMATRON_EVALUATION_ERROR("Schematron evaluation error: {0}"),

ORIGINAL_XML_NOT_SCHEMA_VALID("Original document {0} is not schema valid:{1}"),

CLI_ARGUMENT_NOT_PRESENT_BUT_PI_EXPECTATION("No {0} given at CLI but expectation declared in a xmute pi"),

LOGLEVEL_WRONG("Log level incorrect: {0}. Please choose between OFF, FATAL, ERROR, WARN, INFO, DEBUG, TRACE or ALL (case-insensitive)");

private final String template;
ErrorCode(final String template) {
this.template = template;
}

public String getTemplate() {
return this.template;
}
Expand Down
25 changes: 25 additions & 0 deletions src/main/java/de/kosit/xmlmutate/runner/LogLevel.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package de.kosit.xmlmutate.runner;


import org.apache.logging.log4j.Level;

public enum LogLevel {
/**
* The log levels according to Log4j2
*/
OFF (Level.OFF),
FATAL (Level.FATAL),
ERROR (Level.ERROR),
WARN (Level.WARN),
INFO (Level.INFO),
DEBUG (Level.DEBUG),
TRACE (Level.TRACE),
ALL (Level.ALL);

public final Level level;

LogLevel(final Level level) {
this.level = level;
}

}

0 comments on commit 27232b6

Please sign in to comment.