diff --git a/pom.xml b/pom.xml index a271e30..a007283 100644 --- a/pom.xml +++ b/pom.xml @@ -50,7 +50,7 @@ UTF-8 0.8.3 1.18.6 - 9.9.1-1 + 9.9.1-3 1.7.25 localhost diff --git a/src/main/java/de/kosit/validationtool/api/AcceptRecommendation.java b/src/main/java/de/kosit/validationtool/api/AcceptRecommendation.java new file mode 100644 index 0000000..3d07933 --- /dev/null +++ b/src/main/java/de/kosit/validationtool/api/AcceptRecommendation.java @@ -0,0 +1,21 @@ +package de.kosit.validationtool.api; + +/** + * Status der Empfehlung. + */ +public enum AcceptRecommendation { + /** + * Nicht definiert, weil eine Evaluierung nicht durchgeführt wurde, oder nicht durchgeführt werden konnte. + */ + UNDEFINED, + + /** + * Das Dokument ist gemäß Konfiguration valide und kann akzeptiert werden. + */ + ACCEPTABLE, + + /** + * Das Dokuemnt ist gemäß Konfiguration invalide und sollte NICHT akzeptiert werden. + */ + REJECT +} \ No newline at end of file diff --git a/src/main/java/de/kosit/validationtool/api/Check.java b/src/main/java/de/kosit/validationtool/api/Check.java index c2d8629..17053a2 100644 --- a/src/main/java/de/kosit/validationtool/api/Check.java +++ b/src/main/java/de/kosit/validationtool/api/Check.java @@ -24,9 +24,6 @@ import java.util.stream.Collectors; import org.w3c.dom.Document; -import net.sf.saxon.dom.NodeOverNodeInfo; -import net.sf.saxon.s9api.XdmNode; - /** * Zentrale Schnittstellendefinition für das Prüf-Tool. @@ -42,10 +39,10 @@ public interface Check { * @param input die Resource / XML-Datei, die geprüft werden soll. * @return ein Ergebnis-{@link Document} (readonly) */ - default Document check(Input input) { - final XdmNode node = checkInput(input); + default Document check(final Input input) { + final Result result = checkInput(input); // readonly view of the document!!! - return (Document) NodeOverNodeInfo.wrap(node.getUnderlyingNode()); + return result.getReportDocument(); } /** @@ -54,7 +51,7 @@ public interface Check { * @param input die Resource / XML-Datei, die geprüft werden soll. * @return ein Ergebnis-{@link Document} */ - XdmNode checkInput(Input input); + Result checkInput(Input input); /** * Führt eine Prüfung im Batch-Mode durch. Die Default-Implementierung führt die Prüfung sequentiell aus. Die Ergebnis @@ -63,7 +60,7 @@ public interface Check { * @param input die Eingabe * @return Liste mit Ergebnis-Dokumenten (readonly) */ - default List check(List input) { + default List check(final List input) { return input.stream().map(this::check).collect(Collectors.toList()); } @@ -73,8 +70,9 @@ public interface Check { * @param input die Eingabe * @return Liste mit Ergebnis-Dokumenten */ - default List checkInput(List input) { + default List checkInput(final List input) { return input.stream().map(this::checkInput).collect(Collectors.toList()); } + } diff --git a/src/main/java/de/kosit/validationtool/api/Result.java b/src/main/java/de/kosit/validationtool/api/Result.java new file mode 100644 index 0000000..6d9eef7 --- /dev/null +++ b/src/main/java/de/kosit/validationtool/api/Result.java @@ -0,0 +1,44 @@ +package de.kosit.validationtool.api; + +import org.w3c.dom.Document; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import net.sf.saxon.dom.NodeOverNodeInfo; +import net.sf.saxon.s9api.XdmNode; + +/** + * API Rückgabe Objekt des Ergebnisses des Validierungsprozesses. + * + * @author Andreas Penski + */ +@Getter +@RequiredArgsConstructor +public class Result { + + /** Der generierte Report. */ + private final XdmNode report; + + /** Das evaluierte Ergebnis. */ + private final AcceptRecommendation acceptRecommendation; + + /** + * Gibt den Report als W3C-{@link Document} zurück. + * + * @return der Report + */ + public Document getReportDocument() { + return (Document) NodeOverNodeInfo.wrap(getReport().getUnderlyingNode()); + } + + /** + * Schnellzugriff auf die Empfehlung zur Weiterverarbeitung des Dokuments. + * + * @return true wenn {@link AcceptRecommendation#ACCEPTABLE} + */ + public boolean isAcceptable() { + return AcceptRecommendation.ACCEPTABLE.equals(acceptRecommendation); + } + +} diff --git a/src/main/java/de/kosit/validationtool/cmd/CommandLineApplication.java b/src/main/java/de/kosit/validationtool/cmd/CommandLineApplication.java index 91cb851..41b3c5e 100644 --- a/src/main/java/de/kosit/validationtool/cmd/CommandLineApplication.java +++ b/src/main/java/de/kosit/validationtool/cmd/CommandLineApplication.java @@ -28,6 +28,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.List; import java.util.stream.Collectors; import org.apache.commons.cli.CommandLine; @@ -45,6 +46,7 @@ import lombok.extern.slf4j.Slf4j; import de.kosit.validationtool.api.CheckConfiguration; import de.kosit.validationtool.api.Input; import de.kosit.validationtool.api.InputFactory; +import de.kosit.validationtool.api.Result; import de.kosit.validationtool.cmd.assertions.Assertions; import de.kosit.validationtool.impl.ConversionService; import de.kosit.validationtool.impl.ObjectFactory; @@ -101,7 +103,7 @@ public class CommandLineApplication { * * @param args die Eingabe-Argumente */ - public static void main(String[] args) { + public static void main(final String[] args) { final int resultStatus = mainProgram(args); if (DAEMON_SIGNAL != resultStatus) { System.exit(resultStatus); @@ -114,14 +116,14 @@ public class CommandLineApplication { * * @param args die Eingabe-Argumente */ - static int mainProgram(String[] args) { + static int mainProgram(final String[] args) { int returnValue = 0; - Options options = createOptions(); + final Options options = createOptions(); if (isHelpRequested(args)) { printHelp(options); } else { try { - CommandLineParser parser = new DefaultParser(); + final CommandLineParser parser = new DefaultParser(); final CommandLine cmd = parser.parse(options, args); if (cmd.hasOption(SERVER.getOpt())) { returnValue = startDaemonMode(cmd); @@ -130,7 +132,7 @@ public class CommandLineApplication { } else { returnValue = processActions(cmd); } - } catch (ParseException e) { + } catch (final ParseException e) { log.error("Error processing command line arguments: " + e.getMessage()); printHelp(options); } @@ -138,7 +140,7 @@ public class CommandLineApplication { return returnValue; } - private static int determinePort(CommandLine cmd) { + private static int determinePort(final CommandLine cmd) { int port = 8080; if (checkOptionWithValue(PORT, cmd)) { port = Integer.parseInt(cmd.getOptionValue(PORT.getOpt())); @@ -146,7 +148,7 @@ public class CommandLineApplication { return port; } - private static int determineThreads(CommandLine cmd) { + private static int determineThreads(final CommandLine cmd) { int threads = Runtime.getRuntime().availableProcessors(); if (checkOptionWithValue(WORKER_COUNT, cmd)) { threads = Integer.parseInt(cmd.getOptionValue(WORKER_COUNT.getOpt())); @@ -154,7 +156,7 @@ public class CommandLineApplication { return threads; } - private static String determineHost(CommandLine cmd) { + private static String determineHost(final CommandLine cmd) { String host = "localhost"; if (checkOptionWithValue(HOST, cmd)) { host = cmd.getOptionValue(HOST.getOpt()); @@ -162,15 +164,15 @@ public class CommandLineApplication { return host; } - private static int startDaemonMode(CommandLine cmd) { - Option[] unavailable = new Option[]{PRINT, CHECK_ASSERTIONS, DEBUG, OUTPUT, EXTRACT_HTML}; + private static int startDaemonMode(final CommandLine cmd) { + final Option[] unavailable = new Option[]{PRINT, CHECK_ASSERTIONS, DEBUG, OUTPUT, EXTRACT_HTML}; warnUnusedOptions(cmd, unavailable, true); - Daemon validDaemon = new Daemon(determineDefinition(cmd), determineRepository(cmd), determineHost(cmd), determinePort(cmd), determineThreads(cmd)); + final Daemon validDaemon = new Daemon(determineDefinition(cmd), determineRepository(cmd), determineHost(cmd), determinePort(cmd), determineThreads(cmd)); validDaemon.startServer(); return DAEMON_SIGNAL; } - private static void warnUnusedOptions(CommandLine cmd, Option[] unavailable, boolean daemon) { + private static void warnUnusedOptions(final CommandLine cmd, final Option[] unavailable, final boolean daemon) { Arrays.stream(cmd.getOptions()).filter(o -> ArrayUtils.contains(unavailable, o)).map(o -> "The option " + o.getLongOpt() + " is not available in daemon mode").forEach(log::error); if (daemon && !cmd.getArgList().isEmpty()) { log.info("Ignoring test targets in daemon mode"); @@ -178,30 +180,30 @@ public class CommandLineApplication { } - private static boolean isHelpRequested(String[] args) { - Options helpOptions = createHelpOptions(); + private static boolean isHelpRequested(final String[] args) { + final Options helpOptions = createHelpOptions(); try { - CommandLineParser parser = new DefaultParser(); - CommandLine cmd = parser.parse(helpOptions, args, true); + final CommandLineParser parser = new DefaultParser(); + final CommandLine cmd = parser.parse(helpOptions, args, true); if (cmd.hasOption(HELP.getOpt()) || args.length == 0) { return true; } - } catch (ParseException e) { + } catch (final ParseException e) { // we can ignore that, we just look for the help parameters } return false; } - private static int processActions(CommandLine cmd) { + private static int processActions(final CommandLine cmd) { try { long start = System.currentTimeMillis(); - Option[] unavailable = new Option[]{HOST, PORT, WORKER_COUNT}; + final Option[] unavailable = new Option[]{HOST, PORT, WORKER_COUNT}; warnUnusedOptions(cmd, unavailable, false); - CheckConfiguration d = new CheckConfiguration(determineDefinition(cmd)); + final CheckConfiguration d = new CheckConfiguration(determineDefinition(cmd)); d.setScenarioRepository(determineRepository(cmd)); - InternalCheck check = new InternalCheck(d); - Path outputDirectory = determineOutputDirectory(cmd); + final InternalCheck check = new InternalCheck(d); + final Path outputDirectory = determineOutputDirectory(cmd); if (cmd.hasOption(EXTRACT_HTML.getOpt())) { check.getCheckSteps().add(new ExtractHtmlContentAction(check.getContentRepository(), outputDirectory)); @@ -212,7 +214,7 @@ public class CommandLineApplication { } if (cmd.hasOption(CHECK_ASSERTIONS.getOpt())) { - Assertions assertions = loadAssertions(cmd.getOptionValue(CHECK_ASSERTIONS.getOpt())); + final Assertions assertions = loadAssertions(cmd.getOptionValue(CHECK_ASSERTIONS.getOpt())); check.getCheckSteps().add(new CheckAssertionAction(assertions, ObjectFactory.createProcessor())); } if (cmd.hasOption(PRINT_MEM_STATS.getOpt())) { @@ -222,16 +224,17 @@ public class CommandLineApplication { log.info("Setup completed in {}ms\n", System.currentTimeMillis() - start); final Collection targets = determineTestTargets(cmd); + final List results = new ArrayList<>(); start = System.currentTimeMillis(); - for (Path p : targets) { + for (final Path p : targets) { final Input input = InputFactory.read(p); - check.checkInput(input); + results.add(check.checkInput(input)); } - boolean result = check.printAndEvaluate(); + final boolean result = check.printAndEvaluate(); log.info("Processing {} object(s) completed in {}ms", targets.size(), System.currentTimeMillis() - start); return result ? 0 : 1; - } catch (Exception e) { + } catch (final Exception e) { if (cmd.hasOption(DEBUG.getOpt())) { log.error(e.getMessage(), e); } else { @@ -241,20 +244,20 @@ public class CommandLineApplication { } } - private static Assertions loadAssertions(String optionValue) { - Path p = Paths.get(optionValue); + private static Assertions loadAssertions(final String optionValue) { + final Path p = Paths.get(optionValue); Assertions a = null; if (Files.exists(p)) { - ConversionService c = new ConversionService(); + final ConversionService c = new ConversionService(); c.initialize(de.kosit.validationtool.cmd.assertions.ObjectFactory.class.getPackage()); a = c.readXml(p.toUri(), Assertions.class); } return a; } - private static Path determineOutputDirectory(CommandLine cmd) { + private static Path determineOutputDirectory(final CommandLine cmd) { final String value = cmd.getOptionValue(OUTPUT.getOpt()); - Path fir; + final Path fir; if (StringUtils.isNotBlank(value)) { fir = Paths.get(value); if ((!Files.exists(fir) && !fir.toFile().mkdirs()) || !Files.isDirectory(fir)) { @@ -266,8 +269,8 @@ public class CommandLineApplication { return fir; } - private static Collection determineTestTargets(CommandLine cmd) { - Collection targets = new ArrayList<>(); + private static Collection determineTestTargets(final CommandLine cmd) { + final Collection targets = new ArrayList<>(); if (!cmd.getArgList().isEmpty()) { cmd.getArgList().forEach(e -> targets.addAll(determineTestTarget(e))); } @@ -277,8 +280,8 @@ public class CommandLineApplication { return targets; } - private static Collection determineTestTarget(String s) { - Path d = Paths.get(s); + private static Collection determineTestTarget(final String s) { + final Path d = Paths.get(s); if (Files.isDirectory(d)) { return listDirectoryTargets(d); } else if (Files.exists(d)) { @@ -289,18 +292,18 @@ public class CommandLineApplication { } - private static Collection listDirectoryTargets(Path d) { + private static Collection listDirectoryTargets(final Path d) { try { return Files.list(d).filter(path -> path.toString().endsWith(".xml")).collect(Collectors.toList()); - } catch (IOException e) { + } catch (final IOException e) { throw new IllegalStateException("IOException while list directory content. Can not determine test targets.", e); } } - private static URI determineRepository(CommandLine cmd) { + private static URI determineRepository(final CommandLine cmd) { if (checkOptionWithValue(REPOSITORY, cmd)) { - Path d = Paths.get(cmd.getOptionValue(REPOSITORY.getOpt())); + final Path d = Paths.get(cmd.getOptionValue(REPOSITORY.getOpt())); if (Files.isDirectory(d)) { return d.toUri(); } else { @@ -311,9 +314,9 @@ public class CommandLineApplication { return null; } - private static URI determineDefinition(CommandLine cmd) { + private static URI determineDefinition(final CommandLine cmd) { checkOptionWithValue(SCENARIOS, cmd); - Path f = Paths.get(cmd.getOptionValue(SCENARIOS.getOpt())); + final Path f = Paths.get(cmd.getOptionValue(SCENARIOS.getOpt())); if (Files.isRegularFile(f)) { return f.toAbsolutePath().toUri(); } else { @@ -322,10 +325,10 @@ public class CommandLineApplication { } } - private static boolean checkOptionWithValue(Option option, CommandLine cmd) { - String opt = option.getOpt(); + private static boolean checkOptionWithValue(final Option option, final CommandLine cmd) { + final String opt = option.getOpt(); if (cmd.hasOption(opt)) { - String value = cmd.getOptionValue(opt); + final String value = cmd.getOptionValue(opt); if (StringUtils.isNoneBlank(value)) { return true; } else { @@ -338,20 +341,20 @@ public class CommandLineApplication { return false; } - private static void printHelp(Options options) { + private static void printHelp(final Options options) { // automatically generate the help statement - HelpFormatter formatter = new HelpFormatter(); + final HelpFormatter formatter = new HelpFormatter(); formatter.printHelp("check-tool -s [OPTIONS] [FILE]... ", options, false); } private static Options createHelpOptions() { - Options options = new Options(); + final Options options = new Options(); options.addOption(HELP); return options; } private static Options createOptions() { - Options options = new Options(); + final Options options = new Options(); options.addOption(HELP); options.addOption(SERVER); options.addOption(HOST); diff --git a/src/main/java/de/kosit/validationtool/cmd/InternalCheck.java b/src/main/java/de/kosit/validationtool/cmd/InternalCheck.java index fc835dc..db9a7b1 100644 --- a/src/main/java/de/kosit/validationtool/cmd/InternalCheck.java +++ b/src/main/java/de/kosit/validationtool/cmd/InternalCheck.java @@ -23,11 +23,10 @@ import lombok.extern.slf4j.Slf4j; import de.kosit.validationtool.api.CheckConfiguration; import de.kosit.validationtool.api.Input; +import de.kosit.validationtool.api.Result; import de.kosit.validationtool.impl.DefaultCheck; import de.kosit.validationtool.impl.tasks.CheckAction; -import net.sf.saxon.s9api.XdmNode; - /** * Simple Erweiterung der Klasse {@link DefaultCheck} um das Ergebnis der Assertion-Prüfung auszwerten und auszugeben. * Diese Klasse stellt keine fachlicher Erweiterung des eigentlichen Prüfvorganges dar! @@ -46,7 +45,7 @@ class InternalCheck extends DefaultCheck { * * @param configuration die Konfiguration */ - InternalCheck(CheckConfiguration configuration) { + InternalCheck(final CheckConfiguration configuration) { super(configuration); } @@ -56,23 +55,26 @@ class InternalCheck extends DefaultCheck { * @param input die Prüflinge * @return false wenn es Assertion-Fehler gibt, sonst true */ - public XdmNode checkInput(Input input) { - CheckAction.Bag bag = new CheckAction.Bag(input, createReport()); - XdmNode result = runCheckInternal(bag); + @Override + public Result checkInput(final Input input) { + final CheckAction.Bag bag = new CheckAction.Bag(input, createReport()); + final Result result = runCheckInternal(bag); if (bag.getAssertionResult() != null) { - checkAssertions += bag.getAssertionResult().getObject(); - failedAssertions += bag.getAssertionResult().getErrors().size(); + this.checkAssertions += bag.getAssertionResult().getObject(); + this.failedAssertions += bag.getAssertionResult().getErrors().size(); } return result; } boolean printAndEvaluate() { - if (failedAssertions > 0) { - log.error("Assertion check failed.\n\nAssertions run: {}, Assertions failed: {}\n", checkAssertions, failedAssertions); - } else if (checkAssertions > 0) { - log.info("Assertion check successful.\n\nAssertions run: {}, Assertions failed: {}\n", checkAssertions, failedAssertions); + if (this.failedAssertions > 0) { + log.error("Assertion check failed.\n\nAssertions run: {}, Assertions failed: {}\n", this.checkAssertions, + this.failedAssertions); + } else if (this.checkAssertions > 0) { + log.info("Assertion check successful.\n\nAssertions run: {}, Assertions failed: {}\n", this.checkAssertions, + this.failedAssertions); } - return failedAssertions == 0; + return this.failedAssertions == 0; } } diff --git a/src/main/java/de/kosit/validationtool/impl/DefaultCheck.java b/src/main/java/de/kosit/validationtool/impl/DefaultCheck.java index 4c0aeb6..e540b92 100644 --- a/src/main/java/de/kosit/validationtool/impl/DefaultCheck.java +++ b/src/main/java/de/kosit/validationtool/impl/DefaultCheck.java @@ -28,7 +28,9 @@ import lombok.extern.slf4j.Slf4j; import de.kosit.validationtool.api.Check; import de.kosit.validationtool.api.CheckConfiguration; import de.kosit.validationtool.api.Input; +import de.kosit.validationtool.api.Result; import de.kosit.validationtool.impl.tasks.CheckAction; +import de.kosit.validationtool.impl.tasks.ComputeAcceptanceAction; import de.kosit.validationtool.impl.tasks.CreateReportAction; import de.kosit.validationtool.impl.tasks.DocumentParseAction; import de.kosit.validationtool.impl.tasks.ScenarioSelectionAction; @@ -41,7 +43,6 @@ import de.kosit.validationtool.model.reportInput.EngineType; import de.kosit.validationtool.model.reportInput.ProcessingError; import net.sf.saxon.s9api.Processor; -import net.sf.saxon.s9api.XdmNode; /** * Die Referenz-Implementierung für den Prüfprozess. Nach initialer Konfiguration ist diese Klasse threadsafe und kann @@ -64,7 +65,6 @@ public class DefaultCheck implements Check { private final ConversionService conversionService; - @Getter private final List checkSteps; @@ -88,6 +88,7 @@ public class DefaultCheck implements Check { this.checkSteps.add(new ValidateReportInputAction(this.conversionService, this.contentRepository.getReportInputSchema())); this.checkSteps .add(new CreateReportAction(processor, this.conversionService, this.repository, configuration.getScenarioRepository())); + this.checkSteps.add(new ComputeAcceptanceAction()); } protected static CreateReportInput createReport() { @@ -101,12 +102,12 @@ public class DefaultCheck implements Check { } @Override - public XdmNode checkInput(final Input input) { + public Result checkInput(final Input input) { final CheckAction.Bag t = new CheckAction.Bag(input, createReport()); return runCheckInternal(t); } - protected XdmNode runCheckInternal(final CheckAction.Bag t) { + protected Result runCheckInternal(final CheckAction.Bag t) { final long started = System.currentTimeMillis(); log.info("Checking content of {}", t.getInput().getName()); for (final CheckAction action : this.checkSteps) { @@ -124,10 +125,10 @@ public class DefaultCheck implements Check { } t.setFinished(true); log.info("Finished check of {} in {}ms\n", t.getInput().getName(), System.currentTimeMillis() - started); - return t.getReport(); + return new Result(t.getReport(), t.getAcceptStatus()); } - private static boolean createDocumentIdentification(final CheckAction.Bag transporter) { + private static void createDocumentIdentification(final CheckAction.Bag transporter) { final DocumentIdentificationType i = new DocumentIdentificationType(); final DocumentIdentificationType.DocumentHash h = new DocumentIdentificationType.DocumentHash(); h.setHashAlgorithm(transporter.getInput().getDigestAlgorithm()); @@ -135,6 +136,5 @@ public class DefaultCheck implements Check { i.setDocumentHash(h); i.setDocumentReference(transporter.getInput().getName()); transporter.getReportInput().setDocumentIdentification(i); - return true; } } diff --git a/src/main/java/de/kosit/validationtool/impl/model/BaseScenario.java b/src/main/java/de/kosit/validationtool/impl/model/BaseScenario.java index 7eabdb4..9bf9ec2 100644 --- a/src/main/java/de/kosit/validationtool/impl/model/BaseScenario.java +++ b/src/main/java/de/kosit/validationtool/impl/model/BaseScenario.java @@ -36,7 +36,11 @@ import lombok.Setter; import de.kosit.validationtool.impl.ContentRepository; import de.kosit.validationtool.impl.ScenarioRepository; -import de.kosit.validationtool.model.scenarios.*; +import de.kosit.validationtool.model.scenarios.CreateReportType; +import de.kosit.validationtool.model.scenarios.NamespaceType; +import de.kosit.validationtool.model.scenarios.ResourceType; +import de.kosit.validationtool.model.scenarios.ValidateWithSchematron; +import de.kosit.validationtool.model.scenarios.ValidateWithXmlSchema; import net.sf.saxon.s9api.XPathExecutable; import net.sf.saxon.s9api.XPathSelector; @@ -50,50 +54,63 @@ import net.sf.saxon.s9api.XsltExecutable; */ public abstract class BaseScenario { - private XPathExecutable xPathExecutable; + /** + * Laufzeitinformationen über eine Transformation. + */ + @Getter + @Setter + @AllArgsConstructor + public class Transformation { + private XsltExecutable executable; + + private ResourceType resourceType; + } + + private XPathExecutable matchExecutable; + + private XPathExecutable acceptExecutable; private Schema schema; - private List schematronValidations; - private ContentRepository repository; - private Transformation reportTransformation; /** * Gibt eine Transformation zurück. + * * @return initialisierte Transformation */ public Transformation getReportTransformation() { - if (reportTransformation == null) { + if (this.reportTransformation == null) { final ResourceType resource = getCreateReport().getResource(); - final XsltExecutable executable = repository.loadXsltScript(URI.create(resource.getLocation())); - reportTransformation = new Transformation(executable, resource); + final XsltExecutable executable = this.repository.loadXsltScript(URI.create(resource.getLocation())); + this.reportTransformation = new Transformation(executable, resource); } - return reportTransformation; + return this.reportTransformation; } /** * Lieferrt das Schema zu diesem Szenario. + * * @return das passende Schema */ public Schema getSchema() { - if (schema == null) { + if (this.schema == null) { final List schemaResources = getValidateWithXmlSchema().getResource().stream().map(ResourceType::getLocation) .collect(Collectors.toList()); - schema = repository.createSchema(schemaResources); + this.schema = this.repository.createSchema(schemaResources); } - return schema; + return this.schema; } - /** * Initialisiert das Szenario auf Basis eines [@link ContentRepository} + * * @param repository das Repository mit den Szenario-Artefakten * @param lazy optionales lazy loading der XML-Artefakte * @return true wenn erfolgreich */ - public boolean initialize(ContentRepository repository, boolean lazy) { + public boolean initialize(final ContentRepository repository, final boolean lazy) { this.repository = repository; if (!lazy) { getSchema(); @@ -106,20 +123,21 @@ public abstract class BaseScenario { /** * Liefer eine Liste mit Schematron Validierungs-Transformationen + * * @return liste mit initialisierten Transformationsinformationen */ public List getSchematronValidations() { - if (schematronValidations == null) { - schematronValidations = new ArrayList<>(); + if (this.schematronValidations == null) { + this.schematronValidations = new ArrayList<>(); getValidateWithSchematron().forEach(v -> { if (v.isPsvi()) { throw new NotImplementedException("This implemenation does not support PSVI usage"); } - final XsltExecutable xsltExecutable = repository.loadXsltScript(URI.create(v.getResource().getLocation())); - schematronValidations.add(new Transformation(xsltExecutable, v.getResource())); + final XsltExecutable xsltExecutable = this.repository.loadXsltScript(URI.create(v.getResource().getLocation())); + this.schematronValidations.add(new Transformation(xsltExecutable, v.getResource())); }); } - return schematronValidations; + return this.schematronValidations; } /** @@ -129,11 +147,28 @@ public abstract class BaseScenario { * @see {@link ScenarioRepository#selectScenario(Document)}. */ public XPathSelector getSelector() { - if (xPathExecutable == null) { - final Map namespaces = getNamespace().stream().collect(Collectors.toMap(NamespaceType::getPrefix, NamespaceType::getValue)); - xPathExecutable = repository.createXPath(getMatch(), namespaces); + if (this.matchExecutable == null) { + this.matchExecutable = this.repository.createXPath(getMatch(), prepareNamespaces()); } - return xPathExecutable.load(); + return this.matchExecutable.load(); + } + + /** + * Liefert einen neuen XPath-Selector zur Evaluierung der {@link de.kosit.validationtool.api.AcceptRecommendation}. + * + * @return neuer Selector + */ + public XPathSelector getAcceptSelector() { + if (this.acceptExecutable == null) { + System.out.println(getAcceptMatch()); + System.out.println(prepareNamespaces()); + this.acceptExecutable = this.repository.createXPath(getAcceptMatch(), prepareNamespaces()); + } + return this.acceptExecutable.load(); + } + + private Map prepareNamespaces() { + return getNamespace().stream().collect(Collectors.toMap(NamespaceType::getPrefix, NamespaceType::getValue)); } /** @@ -143,6 +178,8 @@ public abstract class BaseScenario { */ public abstract String getMatch(); + public abstract String getAcceptMatch(); + /** * Getter aus dem schema. * @@ -171,17 +208,4 @@ public abstract class BaseScenario { */ public abstract CreateReportType getCreateReport(); - /** - * Laufzeitinformationen über eine Transformation. - */ - @Getter - @Setter - @AllArgsConstructor - public class Transformation { - - private XsltExecutable executable; - - private ResourceType resourceType; - } - } diff --git a/src/main/java/de/kosit/validationtool/impl/tasks/CheckAction.java b/src/main/java/de/kosit/validationtool/impl/tasks/CheckAction.java index c569663..2063cd7 100644 --- a/src/main/java/de/kosit/validationtool/impl/tasks/CheckAction.java +++ b/src/main/java/de/kosit/validationtool/impl/tasks/CheckAction.java @@ -25,6 +25,7 @@ import java.util.regex.Pattern; import lombok.Getter; import lombok.Setter; +import de.kosit.validationtool.api.AcceptRecommendation; import de.kosit.validationtool.api.Input; import de.kosit.validationtool.impl.model.Result; import de.kosit.validationtool.model.reportInput.CreateReportInput; @@ -43,25 +44,6 @@ import net.sf.saxon.s9api.XdmNode; @FunctionalInterface public interface CheckAction { - /** - * Ausfürhung des Prüfschrittes und Erweiterung der gesammelten Informationen. - * - * @param results die Informationssammlung - */ - void check(Bag results); - - /** - * Ermittlung, ob ein Schritt u.U. ausgelassen werden kann. Die Funktion wird vor der eigentlichen Prüfaktion aufgerufen - * und kann somit eine Ausführung des Prüfschrittes verhindern. Entwickler können diese Funktion überschreiben, um den - * Prüfschritt bedingt auszuführen. - * - * @param results die bisher gesammelten Information - * @return true wenn der Schritt ausgelassen werden soll - */ - default boolean isSkipped(Bag results) { - return false; - } - /** * Transport-Klasse für Eingabe und Ausgabe-Objekte für die einzelnen Prüfschritte. */ @@ -80,6 +62,8 @@ public interface CheckAction { private boolean stopped; + private AcceptRecommendation acceptStatus = AcceptRecommendation.UNDEFINED; + /** Das zu prüfende Dokument */ private Input input; @@ -89,15 +73,16 @@ public interface CheckAction { private Result schemaValidationResult; - public Bag(Input input) { + public Bag(final Input input) { this(input, new CreateReportInput()); } - public Bag(Input input, CreateReportInput reportInput) { + public Bag(final Input input, final CreateReportInput reportInput) { this.input = input; this.reportInput = reportInput; } + /** * Signalisiert einen vorzeitigen Stop der Vearbeitung. */ @@ -107,7 +92,7 @@ public interface CheckAction { /** * Gibt den Namen des Prüflings zurück, dabei werden etwaige Pfadinformationen abgeschnitten. - * + * * @return der Name des Prüflings */ public String getName() { @@ -119,4 +104,24 @@ public interface CheckAction { return fileName; } } + + /** + * Ausfürhung des Prüfschrittes und Erweiterung der gesammelten Informationen. + * + * @param results die Informationssammlung + */ + void check(Bag results); + + /** + * Ermittlung, ob ein Schritt u.U. ausgelassen werden kann. Die Funktion wird vor der eigentlichen Prüfaktion aufgerufen + * und kann somit eine Ausführung des Prüfschrittes verhindern. Entwickler können diese Funktion überschreiben, um den + * Prüfschritt bedingt auszuführen. + * + * @param results die bisher gesammelten Information + * @return true wenn der Schritt ausgelassen werden soll + */ + default boolean isSkipped(final Bag results) { + return false; + } + } diff --git a/src/main/java/de/kosit/validationtool/impl/tasks/ComputeAcceptanceAction.java b/src/main/java/de/kosit/validationtool/impl/tasks/ComputeAcceptanceAction.java new file mode 100644 index 0000000..67d4ae4 --- /dev/null +++ b/src/main/java/de/kosit/validationtool/impl/tasks/ComputeAcceptanceAction.java @@ -0,0 +1,42 @@ +package de.kosit.validationtool.impl.tasks; + +import static org.apache.commons.lang3.StringUtils.isNotBlank; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import de.kosit.validationtool.api.AcceptRecommendation; + +import net.sf.saxon.s9api.XPathSelector; + +/** + * Berechnet die Akzeptanz-Empfehlung gemäß konfigurierten 'acceptMatch' des aktuellen Szenarios. + * + * @author Andreas Penski + */ +@RequiredArgsConstructor +@Slf4j +public class ComputeAcceptanceAction implements CheckAction { + + @Override + public void check(final Bag results) { + final String acceptMatch = results.getScenarioSelectionResult().getObject().getAcceptMatch(); + if (isNotBlank(acceptMatch)) { + + try { + + final XPathSelector selector = results.getScenarioSelectionResult().getObject().getAcceptSelector(); + selector.setContextItem(results.getReport()); + results.setAcceptStatus(selector.effectiveBooleanValue() ? AcceptRecommendation.ACCEPTABLE : AcceptRecommendation.REJECT); + } catch (final Exception e) { + log.error("Fehler bei Evaluierung des Accept-Status: {}", e.getMessage(), e); + } + } + } + + @Override + public boolean isSkipped(final Bag results) { + return results.getScenarioSelectionResult().isInvalid(); + } + +} diff --git a/src/main/model/xsd/scenarios.xsd b/src/main/model/xsd/scenarios.xsd index 9570334..1b2f9d9 100644 --- a/src/main/model/xsd/scenarios.xsd +++ b/src/main/model/xsd/scenarios.xsd @@ -20,7 +20,8 @@ + targetNamespace="http://www.xoev.de/de/validator/framework/1/scenarios" version="1.1.0" elementFormDefault="qualified" + attributeFormDefault="unqualified"> @@ -86,6 +87,8 @@ + + diff --git a/src/test/java/de/kosit/validationtool/impl/DefaultCheckTest.java b/src/test/java/de/kosit/validationtool/impl/DefaultCheckTest.java index 7b61ebc..1e0f69a 100644 --- a/src/test/java/de/kosit/validationtool/impl/DefaultCheckTest.java +++ b/src/test/java/de/kosit/validationtool/impl/DefaultCheckTest.java @@ -33,17 +33,17 @@ import org.junit.Before; import org.junit.Test; import org.w3c.dom.Document; +import de.kosit.validationtool.api.AcceptRecommendation; import de.kosit.validationtool.api.CheckConfiguration; import de.kosit.validationtool.api.Input; - -import net.sf.saxon.s9api.XdmNode; +import de.kosit.validationtool.api.Result; /** * Test das Check-Interface * * @author Andreas Penski */ -public class DefaultCheckTest { +public class DefaultCheckTest extends CheckTest { private static final URL SCENARIO_DEFINITION = ScenarioRepositoryTest.class.getResource("/examples/UBLReady/scenarios-2.xml"); @@ -62,27 +62,30 @@ public class DefaultCheckTest { } @Test - public void testHappyCase() throws Exception { - final XdmNode doc = this.implementation.checkInput(read(VALID_EXAMPLE)); + public void testHappyCase() { + final Result doc = this.implementation.checkInput(read(VALID_EXAMPLE)); assertThat(doc).isNotNull(); + assertThat(doc.getReport()).isNotNull(); + assertThat(doc.isAcceptable()).isFalse(); + assertThat(doc.getAcceptRecommendation()).isEqualTo(AcceptRecommendation.UNDEFINED); } @Test - public void testHappyCaseDocument() throws Exception { + public void testHappyCaseDocument() { final Document doc = this.implementation.check(read(VALID_EXAMPLE)); assertThat(doc).isNotNull(); } @Test - public void testMultipleCase() throws Exception { + public void testMultipleCase() { final List input = IntStream.range(0, MULTI_COUNT).mapToObj(i -> read(VALID_EXAMPLE)).collect(Collectors.toList()); - final List docs = this.implementation.checkInput(input); + final List docs = this.implementation.checkInput(input); assertThat(docs).isNotNull(); assertThat(docs).hasSize(MULTI_COUNT); } @Test - public void testMultipleCaseDocument() throws Exception { + public void testMultipleCaseDocument() { final List input = IntStream.range(0, MULTI_COUNT).mapToObj(i -> read(VALID_EXAMPLE)).collect(Collectors.toList()); final List docs = this.implementation.check(input); assertThat(docs).isNotNull(); diff --git a/src/test/java/de/kosit/validationtool/impl/Helper.java b/src/test/java/de/kosit/validationtool/impl/Helper.java index 22b5925..b5d313a 100644 --- a/src/test/java/de/kosit/validationtool/impl/Helper.java +++ b/src/test/java/de/kosit/validationtool/impl/Helper.java @@ -39,6 +39,23 @@ import net.sf.saxon.s9api.XdmNode; */ public class Helper { + public static class Simple { + + public static final URI ROOT = EXAMPLES_DIR.resolve("simple/"); + + public static final URI SIMPLE_VALID = Simple.ROOT.resolve("input/simple.xml"); + + public static final URI FOO = Simple.ROOT.resolve("input/foo.xml"); + + public static final URI SCENARIOS = ROOT.resolve("scenarios.xml"); + + public static final URI REPOSITORY = ROOT.resolve("repository/"); + + public static final URI INVALID = ROOT.resolve("input/simple-invalid.xml"); + + public static final URI UNKNOWN = ROOT.resolve("input/unknown.xml"); + } + public static final URI SOURCE_ROOT = Paths.get("src/main/resources").toUri(); public static final URI MODEL_ROOT = Paths.get("src/main/model").toUri(); diff --git a/src/test/java/de/kosit/validationtool/impl/SimpleScenarioCheck.java b/src/test/java/de/kosit/validationtool/impl/SimpleScenarioCheck.java new file mode 100644 index 0000000..7f42f2c --- /dev/null +++ b/src/test/java/de/kosit/validationtool/impl/SimpleScenarioCheck.java @@ -0,0 +1,60 @@ +package de.kosit.validationtool.impl; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.net.MalformedURLException; +import java.net.URISyntaxException; + +import org.junit.Before; +import org.junit.Test; + +import de.kosit.validationtool.api.AcceptRecommendation; +import de.kosit.validationtool.api.CheckConfiguration; +import de.kosit.validationtool.api.InputFactory; +import de.kosit.validationtool.api.Result; +import de.kosit.validationtool.impl.Helper.Simple; + +/** + * Prüft die Funktionen des Validator auf Basis eines reduzierten Szenarios. + * + * @author Andreas Penski + */ +public class SimpleScenarioCheck { + + private DefaultCheck implementation; + + @Before + public void setup() throws URISyntaxException { + final CheckConfiguration d = new CheckConfiguration(Simple.SCENARIOS); + d.setScenarioRepository(Simple.REPOSITORY); + this.implementation = new DefaultCheck(d); + } + + @Test + public void testSimple() throws MalformedURLException { + final Result result = this.implementation.checkInput(InputFactory.read(Simple.SIMPLE_VALID.toURL())); + assertThat(result).isNotNull(); + assertThat(result.getAcceptRecommendation()).isEqualTo(AcceptRecommendation.ACCEPTABLE); + } + + @Test + public void testInvalid() throws MalformedURLException { + final Result result = this.implementation.checkInput(InputFactory.read(Simple.INVALID.toURL())); + assertThat(result).isNotNull(); + assertThat(result.getAcceptRecommendation()).isEqualTo(AcceptRecommendation.REJECT); + } + + @Test + public void testUnknown() throws MalformedURLException { + final Result result = this.implementation.checkInput(InputFactory.read(Simple.UNKNOWN.toURL())); + assertThat(result).isNotNull(); + assertThat(result.getAcceptRecommendation()).isEqualTo(AcceptRecommendation.UNDEFINED); + } + + @Test + public void testWithoutAcceptMatch() throws MalformedURLException { + final Result result = this.implementation.checkInput(InputFactory.read(Simple.FOO.toURL())); + assertThat(result).isNotNull(); + assertThat(result.getAcceptRecommendation()).isEqualTo(AcceptRecommendation.UNDEFINED); + } +} diff --git a/src/test/resources/examples/simple/input/foo.xml b/src/test/resources/examples/simple/input/foo.xml new file mode 100644 index 0000000..b84fe4f --- /dev/null +++ b/src/test/resources/examples/simple/input/foo.xml @@ -0,0 +1,5 @@ + + + + asldkfj + \ No newline at end of file diff --git a/src/test/resources/examples/simple/input/simple-invalid.xml b/src/test/resources/examples/simple/input/simple-invalid.xml new file mode 100644 index 0000000..4844ae9 --- /dev/null +++ b/src/test/resources/examples/simple/input/simple-invalid.xml @@ -0,0 +1,6 @@ + + + + asldkfj + + \ No newline at end of file diff --git a/src/test/resources/examples/simple/input/simple.xml b/src/test/resources/examples/simple/input/simple.xml new file mode 100644 index 0000000..63032b1 --- /dev/null +++ b/src/test/resources/examples/simple/input/simple.xml @@ -0,0 +1,5 @@ + + + + asldkfj + \ No newline at end of file diff --git a/src/test/resources/examples/simple/input/unknown.xml b/src/test/resources/examples/simple/input/unknown.xml new file mode 100644 index 0000000..3cfc388 --- /dev/null +++ b/src/test/resources/examples/simple/input/unknown.xml @@ -0,0 +1,5 @@ + + + + asldkfj + \ No newline at end of file diff --git a/src/test/resources/examples/simple/repository/report.xsl b/src/test/resources/examples/simple/repository/report.xsl new file mode 100644 index 0000000..a402938 --- /dev/null +++ b/src/test/resources/examples/simple/repository/report.xsl @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/examples/simple/repository/simple.xsd b/src/test/resources/examples/simple/repository/simple.xsd new file mode 100644 index 0000000..b7f2b68 --- /dev/null +++ b/src/test/resources/examples/simple/repository/simple.xsd @@ -0,0 +1,14 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/examples/simple/scenarios.xml b/src/test/resources/examples/simple/scenarios.xml new file mode 100644 index 0000000..47e5ec8 --- /dev/null +++ b/src/test/resources/examples/simple/scenarios.xml @@ -0,0 +1,84 @@ + + + + + HTML-TestSuite + 2017-08-08 + + Szenario für Tests + + + + Simple + + Nur Schemaprüfung. + + http://www.xoev.de/de/validator/framework/1/createreportinput + http://validator.kosit.de/test-sample + http://validator.kosit.de/test-report + /test:simple + + + + Sample Schema + simple.xsd + + + + + Report für eRechnung + report.xsl + + + count(//cri:xmlSyntaxError) = 0 + + + + NoAcceptMatch + + Nur Schemaprüfung. Keine AcceptMatch deklaration + Testen, ob auch alte Konfiguration funktionioeren + + http://validator.kosit.de/test-sample + /test:foo + + + + Sample Schema + simple.xsd + + + + + Report für eRechnung + report.xsl + + + + + + + + default + report.xsl + + + +
Szenario für Tests
Nur Schemaprüfung.
Nur Schemaprüfung. Keine AcceptMatch deklaration
Testen, ob auch alte Konfiguration funktionioeren