mirror of
https://github.com/itplr-kosit/validator.git
synced 2026-05-26 01:05:38 +00:00
(enhance) introduce resolving strategy (configurable xml security); introduce API configuration
This commit is contained in:
parent
7a86f049ac
commit
35c0797898
67 changed files with 2441 additions and 845 deletions
3
.idea/misc.xml
generated
3
.idea/misc.xml
generated
|
|
@ -1,6 +1,9 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||||
|
<component name="JavaScriptSettings">
|
||||||
|
<option name="languageLevel" value="ES6" />
|
||||||
|
</component>
|
||||||
<component name="MarkdownProjectSettings">
|
<component name="MarkdownProjectSettings">
|
||||||
<PreviewSettings splitEditorLayout="SPLIT" splitEditorPreview="PREVIEW" useGrayscaleRendering="false" zoomFactor="1.0" maxImageWidth="0" showGitHubPageIfSynced="false" allowBrowsingInPreview="false" synchronizePreviewPosition="true" highlightPreviewType="LINE" highlightFadeOut="5" highlightOnTyping="true" synchronizeSourcePosition="true">
|
<PreviewSettings splitEditorLayout="SPLIT" splitEditorPreview="PREVIEW" useGrayscaleRendering="false" zoomFactor="1.0" maxImageWidth="0" showGitHubPageIfSynced="false" allowBrowsingInPreview="false" synchronizePreviewPosition="true" highlightPreviewType="LINE" highlightFadeOut="5" highlightOnTyping="true" synchronizeSourcePosition="true">
|
||||||
<PanelProvider>
|
<PanelProvider>
|
||||||
|
|
|
||||||
|
|
@ -21,18 +21,17 @@ package de.kosit.validationtool.api;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import de.kosit.validationtool.config.LoadConfiguration;
|
import de.kosit.validationtool.config.ConfigurationLoader;
|
||||||
import de.kosit.validationtool.impl.ContentRepository;
|
import de.kosit.validationtool.impl.ContentRepository;
|
||||||
import de.kosit.validationtool.impl.Scenario;
|
import de.kosit.validationtool.impl.Scenario;
|
||||||
|
|
||||||
import net.sf.saxon.s9api.Processor;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Zentrale Konfigration einer Prüf-Instanz.
|
* Zentrale Konfigration einer Prüf-Instanz.
|
||||||
*
|
*
|
||||||
|
|
@ -56,11 +55,13 @@ public class CheckConfiguration implements Configuration {
|
||||||
*/
|
*/
|
||||||
private URI scenarioRepository;
|
private URI scenarioRepository;
|
||||||
|
|
||||||
private LoadConfiguration delegate;
|
private ConfigurationLoader loader;
|
||||||
|
|
||||||
private LoadConfiguration getDelegate() {
|
private Configuration delegate;
|
||||||
|
|
||||||
|
private Configuration getDelegate() {
|
||||||
if (this.delegate == null) {
|
if (this.delegate == null) {
|
||||||
this.delegate = Configuration.load(this.scenarioDefinition, this.scenarioRepository);
|
this.delegate = Configuration.load(this.scenarioDefinition, this.scenarioRepository).build();
|
||||||
}
|
}
|
||||||
return this.delegate;
|
return this.delegate;
|
||||||
}
|
}
|
||||||
|
|
@ -76,13 +77,13 @@ public class CheckConfiguration implements Configuration {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void build() {
|
public String getDate() {
|
||||||
getDelegate().build();
|
return getDelegate().getDate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getDate() {
|
public Map<String, Object> getAdditionalParameters() {
|
||||||
return getDelegate().getDate();
|
return this.delegate.getAdditionalParameters();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -95,10 +96,7 @@ public class CheckConfiguration implements Configuration {
|
||||||
return getDelegate().getAuthor();
|
return getDelegate().getAuthor();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Processor getProcessor() {
|
|
||||||
return getDelegate().getProcessor();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ContentRepository getContentRepository() {
|
public ContentRepository getContentRepository() {
|
||||||
|
|
|
||||||
|
|
@ -2,20 +2,19 @@ package de.kosit.validationtool.api;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import de.kosit.validationtool.config.ConfigurationBuilder;
|
import de.kosit.validationtool.config.ConfigurationBuilder;
|
||||||
import de.kosit.validationtool.config.LoadConfiguration;
|
import de.kosit.validationtool.config.ConfigurationLoader;
|
||||||
import de.kosit.validationtool.impl.ContentRepository;
|
import de.kosit.validationtool.impl.ContentRepository;
|
||||||
import de.kosit.validationtool.impl.Scenario;
|
import de.kosit.validationtool.impl.Scenario;
|
||||||
|
|
||||||
import net.sf.saxon.s9api.Processor;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configuration of the actual {@link Check} instance. This is a contruct and can be used implemented by custom
|
* Configuration of the actual {@link Check} instance. This is an interface and can be implemented by custom
|
||||||
* configuration classes. There are two implementations supported out of the box:
|
* configuration classes. There are two implementations supported out of the box:
|
||||||
*
|
*
|
||||||
* <ol>
|
* <ol>
|
||||||
* <li>{@link LoadConfiguration} implements loading {@link Check} configurations from a scenario.xml file</li>
|
* <li>{@link ConfigurationLoader} implements loading {@link Check} configurations from a scenario.xml file</li>
|
||||||
* <li>Using a builder style api {@link de.kosit.validationtool.config.ConfigurationBuilder}to configure the
|
* <li>Using a builder style api {@link de.kosit.validationtool.config.ConfigurationBuilder}to configure the
|
||||||
* {@link Check}</li>
|
* {@link Check}</li>
|
||||||
* </ol>
|
* </ol>
|
||||||
|
|
@ -27,33 +26,77 @@ import net.sf.saxon.s9api.Processor;
|
||||||
|
|
||||||
public interface Configuration {
|
public interface Configuration {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of configured scenarios.
|
||||||
|
*
|
||||||
|
* @return the list of scenarios
|
||||||
|
*/
|
||||||
List<Scenario> getScenarios();
|
List<Scenario> getScenarios();
|
||||||
|
|
||||||
static LoadConfiguration load(final URI scenarioDefinition) {
|
/**
|
||||||
|
* Returns the configured fallback scenario to use, in case no configured scenario match.
|
||||||
|
*
|
||||||
|
* @return the fallback scenario
|
||||||
|
*/
|
||||||
|
Scenario getFallbackScenario();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the author of this configuration.
|
||||||
|
*
|
||||||
|
* @return the author
|
||||||
|
*/
|
||||||
|
String getAuthor();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the name of the specification
|
||||||
|
*
|
||||||
|
* @return the name
|
||||||
|
*/
|
||||||
|
String getName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The creation date of the config
|
||||||
|
*
|
||||||
|
* @return the date
|
||||||
|
*/
|
||||||
|
String getDate();
|
||||||
|
|
||||||
|
Map<String, Object> getAdditionalParameters();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The content repository including resolving strategies.
|
||||||
|
*
|
||||||
|
* @return the configured {@link ContentRepository}
|
||||||
|
*/
|
||||||
|
ContentRepository getContentRepository();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads an XML based scenario definition from the file specified via URI.
|
||||||
|
*
|
||||||
|
* @param scenarioDefinition the XML file with scenario definition
|
||||||
|
* @return the loaded configuration
|
||||||
|
*/
|
||||||
|
static ConfigurationLoader load(final URI scenarioDefinition) {
|
||||||
return load(scenarioDefinition, null);
|
return load(scenarioDefinition, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
static LoadConfiguration load(final URI scenarioDefinition, final URI repository) {
|
/**
|
||||||
final LoadConfiguration config = new LoadConfiguration(scenarioDefinition, repository);
|
* Loads an XML based scenario definition from the file with an specific repository / source location specified via
|
||||||
config.build();
|
* URIs.
|
||||||
return config;
|
*
|
||||||
|
* @param scenarioDefinition the XML file with scenario definition
|
||||||
|
* @return the loaded configuration
|
||||||
|
*/
|
||||||
|
static ConfigurationLoader load(final URI scenarioDefinition, final URI repository) {
|
||||||
|
return new ConfigurationLoader(scenarioDefinition, repository);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a {@link Configuration} based on a builder style API using {@link ConfigurationBuilder}
|
||||||
|
*
|
||||||
|
* @return the Builder
|
||||||
|
*/
|
||||||
static ConfigurationBuilder create() {
|
static ConfigurationBuilder create() {
|
||||||
return new ConfigurationBuilder();
|
return new ConfigurationBuilder();
|
||||||
}
|
}
|
||||||
|
|
||||||
Scenario getFallbackScenario();
|
|
||||||
|
|
||||||
void build();
|
|
||||||
|
|
||||||
String getAuthor();
|
|
||||||
|
|
||||||
String getName();
|
|
||||||
|
|
||||||
String getDate();
|
|
||||||
|
|
||||||
Processor getProcessor();
|
|
||||||
|
|
||||||
ContentRepository getContentRepository();
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@
|
||||||
package de.kosit.validationtool.api;
|
package de.kosit.validationtool.api;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
import javax.xml.transform.Source;
|
import javax.xml.transform.Source;
|
||||||
|
|
||||||
|
|
@ -54,10 +53,10 @@ public interface Input {
|
||||||
String getDigestAlgorithm();
|
String getDigestAlgorithm();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Opens a new {@link InputStream } for this input which carries the actual data
|
* Creates a new {@link Source } for this input which carries the actual data
|
||||||
*
|
*
|
||||||
* @return an open {@link InputStream}
|
* @return an open {@link Source}
|
||||||
* @throws IOException on I/O while opening the stream
|
* @throws IOException on I/O while opening the source
|
||||||
*/
|
*/
|
||||||
Source getSource() throws IOException;
|
Source getSource() throws IOException;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -54,10 +54,6 @@ public class InputFactory {
|
||||||
|
|
||||||
static final String DEFAULT_ALGORITH = "SHA-256";
|
static final String DEFAULT_ALGORITH = "SHA-256";
|
||||||
|
|
||||||
private static final int EOF = -1;
|
|
||||||
|
|
||||||
private static final int DEFAULT_BUFFER_SIZE = 4096;
|
|
||||||
|
|
||||||
private static final String MESSAGE_OPEN_STREAM_ERROR = "Can not open stream from";
|
private static final String MESSAGE_OPEN_STREAM_ERROR = "Can not open stream from";
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
|
|
@ -108,7 +104,6 @@ public class InputFactory {
|
||||||
return read(file, DEFAULT_ALGORITH);
|
return read(file, DEFAULT_ALGORITH);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Liest einen Prüfling von der übergebenen URI. Es wird der Default-Prüfsummenalgorithmus zur Ermittlung der Prüfsumme
|
* Liest einen Prüfling von der übergebenen URI. Es wird der Default-Prüfsummenalgorithmus zur Ermittlung der Prüfsumme
|
||||||
* genutzt.
|
* genutzt.
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,64 @@
|
||||||
|
package de.kosit.validationtool.api;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
|
||||||
|
import javax.xml.transform.URIResolver;
|
||||||
|
import javax.xml.validation.Schema;
|
||||||
|
import javax.xml.validation.SchemaFactory;
|
||||||
|
import javax.xml.validation.Validator;
|
||||||
|
|
||||||
|
import net.sf.saxon.s9api.Processor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Centralized construction and configuration of XML related infrastructore components. The KoSIT Validator provides out
|
||||||
|
* of the box implementaions with various security levels.
|
||||||
|
*
|
||||||
|
* If you decide to implement a custom strategy, please be aware of XML security within your stack. The validator
|
||||||
|
* components beyond this strategy asume secured implementation of the interfaces provided by this strategy. There is no
|
||||||
|
* effort to mitigate or prevent xml related security issues such as XXE, loading external sources etc.
|
||||||
|
*
|
||||||
|
* @see de.kosit.validationtool.impl.ResolvingMode
|
||||||
|
* @author Andreas Penski
|
||||||
|
*/
|
||||||
|
public interface ResolvingConfigurationStrategy {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a preconfigured {@link SchemaFactory} for loading {@link javax.xml.validation.Schema} objects. The
|
||||||
|
* implementation is responsible for xml security. Take care
|
||||||
|
*
|
||||||
|
* @return preconfigured {@link SchemaFactory}
|
||||||
|
*/
|
||||||
|
SchemaFactory createSchemaFactory();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a preconfigured {@link Processor Saxon Processor} for various tasks within the Validator. The validator
|
||||||
|
* leverages the saxon s9api for internal processing e.g. xml reading and writing. So this is the main object to secure
|
||||||
|
* for reading, transforming and writing xml files.
|
||||||
|
*
|
||||||
|
* @return a preconfigured {@link Processor}
|
||||||
|
*/
|
||||||
|
Processor createProcessor();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a specific implementation for resolving referenced objects in XML files. The URIResolver, it is used for
|
||||||
|
* dereferencing an absolute URI (after resolution) to return a {@link javax.xml.transform.Source}. It <b>can</b> be
|
||||||
|
* used for resolving relative URIs against a base URI or restrict access to certain URIs.
|
||||||
|
* <p>
|
||||||
|
* This URIResolver is used to dereference the URIs appearing in <code>xsl:import</code>, <code>xsl:include</code>, and
|
||||||
|
* <code>xsl:import-schema</code> declarations.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @return a preconfigured {@link URIResolver}
|
||||||
|
*/
|
||||||
|
URIResolver createResolver(URI scenarioRepository);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a preconfigured {@link Validator } instance for a given schema for xml file validation. The implementation
|
||||||
|
* takes care about security and reference resolving strategies.
|
||||||
|
*
|
||||||
|
* @param schema the scheme to create a {@link Validator} for
|
||||||
|
* @return a preconfigured {@link Validator}
|
||||||
|
*/
|
||||||
|
Validator createValidator(Schema schema);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -42,12 +42,15 @@ import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import de.kosit.validationtool.api.CheckConfiguration;
|
import de.kosit.validationtool.api.Configuration;
|
||||||
import de.kosit.validationtool.api.Input;
|
import de.kosit.validationtool.api.Input;
|
||||||
import de.kosit.validationtool.api.InputFactory;
|
import de.kosit.validationtool.api.InputFactory;
|
||||||
import de.kosit.validationtool.cmd.assertions.Assertions;
|
import de.kosit.validationtool.cmd.assertions.Assertions;
|
||||||
|
import de.kosit.validationtool.config.ConfigurationLoader;
|
||||||
|
import de.kosit.validationtool.daemon.Daemon;
|
||||||
import de.kosit.validationtool.impl.ConversionService;
|
import de.kosit.validationtool.impl.ConversionService;
|
||||||
import de.kosit.validationtool.impl.ObjectFactory;
|
|
||||||
|
import net.sf.saxon.s9api.Processor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Commandline Version des Prüftools. Parsed die Kommandozeile und führt die konfigurierten Aktionen aus.
|
* Commandline Version des Prüftools. Parsed die Kommandozeile und führt die konfigurierten Aktionen aus.
|
||||||
|
|
@ -169,9 +172,9 @@ public class CommandLineApplication {
|
||||||
private static int startDaemonMode(final CommandLine cmd) {
|
private static int startDaemonMode(final CommandLine cmd) {
|
||||||
final Option[] unavailable = new Option[] { PRINT, CHECK_ASSERTIONS, DEBUG, OUTPUT, EXTRACT_HTML };
|
final Option[] unavailable = new Option[] { PRINT, CHECK_ASSERTIONS, DEBUG, OUTPUT, EXTRACT_HTML };
|
||||||
warnUnusedOptions(cmd, unavailable, true);
|
warnUnusedOptions(cmd, unavailable, true);
|
||||||
final Daemon validDaemon = new Daemon(determineDefinition(cmd), determineRepository(cmd), determineHost(cmd), determinePort(cmd),
|
final ConfigurationLoader config = Configuration.load(determineDefinition(cmd), determineRepository(cmd));
|
||||||
determineThreads(cmd));
|
final Daemon validDaemon = new Daemon(determineHost(cmd), determinePort(cmd), determineThreads(cmd));
|
||||||
validDaemon.startServer();
|
validDaemon.startServer(config.build());
|
||||||
return DAEMON_SIGNAL;
|
return DAEMON_SIGNAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -203,25 +206,26 @@ public class CommandLineApplication {
|
||||||
long start = System.currentTimeMillis();
|
long start = System.currentTimeMillis();
|
||||||
final Option[] unavailable = new Option[] { HOST, PORT, WORKER_COUNT };
|
final Option[] unavailable = new Option[] { HOST, PORT, WORKER_COUNT };
|
||||||
warnUnusedOptions(cmd, unavailable, false);
|
warnUnusedOptions(cmd, unavailable, false);
|
||||||
final CheckConfiguration d = new CheckConfiguration(determineDefinition(cmd));
|
final Configuration config = Configuration.load(determineDefinition(cmd), determineRepository(cmd)).build();
|
||||||
d.setScenarioRepository(determineRepository(cmd));
|
|
||||||
final InternalCheck check = new InternalCheck(d);
|
final InternalCheck check = new InternalCheck(config);
|
||||||
final Path outputDirectory = determineOutputDirectory(cmd);
|
final Path outputDirectory = determineOutputDirectory(cmd);
|
||||||
|
|
||||||
|
final Processor processor = config.getContentRepository().getProcessor();
|
||||||
if (cmd.hasOption(EXTRACT_HTML.getOpt())) {
|
if (cmd.hasOption(EXTRACT_HTML.getOpt())) {
|
||||||
check.getCheckSteps().add(new ExtractHtmlContentAction(check.getContentRepository(), outputDirectory));
|
check.getCheckSteps().add(new ExtractHtmlContentAction(processor, outputDirectory));
|
||||||
}
|
}
|
||||||
check.getCheckSteps().add(new SerializeReportAction(outputDirectory));
|
check.getCheckSteps().add(new SerializeReportAction(outputDirectory, processor));
|
||||||
if (cmd.hasOption(SERIALIZE_REPORT_INPUT.getOpt())) {
|
if (cmd.hasOption(SERIALIZE_REPORT_INPUT.getOpt())) {
|
||||||
check.getCheckSteps().add(new SerializeReportInputAction(outputDirectory, check.getConversionService()));
|
check.getCheckSteps().add(new SerializeReportInputAction(outputDirectory, check.getConversionService()));
|
||||||
}
|
}
|
||||||
if (cmd.hasOption(PRINT.getOpt())) {
|
if (cmd.hasOption(PRINT.getOpt())) {
|
||||||
check.getCheckSteps().add(new PrintReportAction());
|
check.getCheckSteps().add(new PrintReportAction(processor));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cmd.hasOption(CHECK_ASSERTIONS.getOpt())) {
|
if (cmd.hasOption(CHECK_ASSERTIONS.getOpt())) {
|
||||||
final 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()));
|
check.getCheckSteps().add(new CheckAssertionAction(assertions, processor));
|
||||||
}
|
}
|
||||||
if (cmd.hasOption(PRINT_MEM_STATS.getOpt())) {
|
if (cmd.hasOption(PRINT_MEM_STATS.getOpt())) {
|
||||||
check.getCheckSteps().add(new PrintMemoryStats());
|
check.getCheckSteps().add(new PrintMemoryStats());
|
||||||
|
|
|
||||||
|
|
@ -1,199 +0,0 @@
|
||||||
package de.kosit.validationtool.cmd;
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.net.InetSocketAddress;
|
|
||||||
import java.net.URI;
|
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
|
||||||
|
|
||||||
import javax.xml.transform.Transformer;
|
|
||||||
import javax.xml.transform.TransformerException;
|
|
||||||
import javax.xml.transform.dom.DOMSource;
|
|
||||||
import javax.xml.transform.stream.StreamResult;
|
|
||||||
|
|
||||||
import org.w3c.dom.Document;
|
|
||||||
|
|
||||||
import com.sun.net.httpserver.HttpExchange;
|
|
||||||
import com.sun.net.httpserver.HttpHandler;
|
|
||||||
import com.sun.net.httpserver.HttpServer;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.Setter;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
|
|
||||||
import de.kosit.validationtool.api.Check;
|
|
||||||
import de.kosit.validationtool.api.CheckConfiguration;
|
|
||||||
import de.kosit.validationtool.api.Configuration;
|
|
||||||
import de.kosit.validationtool.api.InputFactory;
|
|
||||||
import de.kosit.validationtool.impl.DefaultCheck;
|
|
||||||
import de.kosit.validationtool.impl.ObjectFactory;
|
|
||||||
import de.kosit.validationtool.impl.input.SourceInput;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* HTTP-Daemon für die Bereitstellung der Prüf-Funktionalität via http.
|
|
||||||
*
|
|
||||||
* @author Roula Antoun
|
|
||||||
*/
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
@Setter
|
|
||||||
@Getter
|
|
||||||
@Slf4j
|
|
||||||
class Daemon {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wir benötigen einen Handler, der zur Verarbeitung von HTTP-Anforderungen aufgerufen wird um hier die Verarbeitung des
|
|
||||||
* POST Request zu realisieren.
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
private static class HttpServerHandler implements HttpHandler {
|
|
||||||
|
|
||||||
private static final AtomicLong counter = new AtomicLong(0);
|
|
||||||
|
|
||||||
private final Check implemenation;
|
|
||||||
|
|
||||||
HttpServerHandler(final Check check) {
|
|
||||||
this.implemenation = check;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Methode, die eine gegebene Anforderung verarbeitet und eine entsprechende Antwort generiert
|
|
||||||
*
|
|
||||||
* @param httpExchange kapselt eine empfangene HTTP-Anforderung und eine Antwort, die in einem Exchange generiert werden
|
|
||||||
* soll.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void handle(final HttpExchange httpExchange) throws IOException {
|
|
||||||
try {
|
|
||||||
log.debug("Incoming request");
|
|
||||||
final String requestMethod = httpExchange.getRequestMethod();
|
|
||||||
if (requestMethod.equals("POST")) {
|
|
||||||
final InputStream inputStream = httpExchange.getRequestBody();
|
|
||||||
final SourceInput serverInput = (SourceInput) InputFactory.read(inputStream, "Prüfling" + counter.incrementAndGet());
|
|
||||||
|
|
||||||
if (inputStream.available() > 0) {
|
|
||||||
writeOutputstreamArray(httpExchange, this.implemenation.check(serverInput));
|
|
||||||
} else {
|
|
||||||
writeError(httpExchange, 400, "XML-Inhalt erforderlich!");
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
writeError(httpExchange, 405, "Es ist nur die POST-Methode erlaubt!");
|
|
||||||
}
|
|
||||||
} catch (final Exception e) {
|
|
||||||
writeError(httpExchange, 500, "Interner Fehler bei der Verarbeitung des Requests: " + e.getMessage());
|
|
||||||
log.error("Es ist ein Fehler aufgetreten. Das Dokument kann nicht geprüft werden", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wir benötigen einen Handler, der zur Verarbeitung von HTTP-Anforderungen aufgerufen wird , und hier für Verarbeitung
|
|
||||||
* das GET Request um Health-Endpunkt zu erstellen. Die Klasse HealthHandler implementiert diese Schnittstelle
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
static class HealthHandler implements HttpHandler {
|
|
||||||
|
|
||||||
private final Configuration scenarios;
|
|
||||||
|
|
||||||
HealthHandler(final Configuration config) {
|
|
||||||
this.scenarios = config;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void handle(final HttpExchange httpExchange) throws IOException {
|
|
||||||
final Health health = new Health(this.scenarios);
|
|
||||||
final Document doc = health.writeHealthXml();
|
|
||||||
try {
|
|
||||||
writeOutputstreamArray(httpExchange, doc);
|
|
||||||
} catch (final TransformerException e) {
|
|
||||||
writeError(httpExchange, 500, e.getMessage());
|
|
||||||
log.error("Fehler beim Erzeugen der Status-Information", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private final URI scenarioDefinition;
|
|
||||||
|
|
||||||
private final URI repository;
|
|
||||||
|
|
||||||
private final String hostName;
|
|
||||||
|
|
||||||
private final int port;
|
|
||||||
|
|
||||||
private final int threadCount;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Methode, die die Antwort als String-Text schreibt
|
|
||||||
*
|
|
||||||
* @param httpExchange um den Antwort Body zu erhalten
|
|
||||||
* @param rCode der Code-Status
|
|
||||||
* @param response die String antwort, die ich anzeigen möchte
|
|
||||||
*/
|
|
||||||
private static void writeError(final HttpExchange httpExchange, final int rCode, final String response) throws IOException {
|
|
||||||
httpExchange.sendResponseHeaders(rCode, response.length());
|
|
||||||
final OutputStream os = httpExchange.getResponseBody();
|
|
||||||
os.write(response.getBytes());
|
|
||||||
os.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Methode, die die Antwort als String-Text schreibt
|
|
||||||
*
|
|
||||||
* @param httpExchange um den Antwort Body zu erhalten
|
|
||||||
* @param doc der Report
|
|
||||||
*/
|
|
||||||
private static void writeOutputstreamArray(final HttpExchange httpExchange, final Document doc)
|
|
||||||
throws IOException, TransformerException {
|
|
||||||
final byte[] bytes = serialize(doc);
|
|
||||||
final OutputStream os = httpExchange.getResponseBody();
|
|
||||||
httpExchange.getResponseHeaders().add("Content-Type", "application/xml");
|
|
||||||
httpExchange.sendResponseHeaders(200, bytes.length);
|
|
||||||
os.write(bytes);
|
|
||||||
os.close();
|
|
||||||
log.debug("Xml File erzeugen ist Fertig ");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Methode zum Serialisieren des Dokuments.
|
|
||||||
*
|
|
||||||
* @param report Vom Typ Dokument, aka Report .
|
|
||||||
*/
|
|
||||||
private static byte[] serialize(final Document report) throws TransformerException {
|
|
||||||
|
|
||||||
try ( final ByteArrayOutputStream bArrayOS = new ByteArrayOutputStream() ) {
|
|
||||||
final DOMSource source = new DOMSource(report);
|
|
||||||
final StreamResult streamResult = new StreamResult(bArrayOS);
|
|
||||||
final Transformer transformer = ObjectFactory.createTransformer(true);
|
|
||||||
transformer.transform(source, streamResult);
|
|
||||||
return bArrayOS.toByteArray();
|
|
||||||
} catch (final IOException e) {
|
|
||||||
log.error("Report {}", e.getMessage(), e);
|
|
||||||
throw new IllegalStateException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Methode zum Starten des Servers
|
|
||||||
*/
|
|
||||||
void startServer() {
|
|
||||||
final CheckConfiguration config = new CheckConfiguration(this.scenarioDefinition);
|
|
||||||
config.setScenarioRepository(this.repository);
|
|
||||||
HttpServer server = null;
|
|
||||||
try {
|
|
||||||
server = HttpServer.create(new InetSocketAddress(this.hostName, this.port), 0);
|
|
||||||
final DefaultCheck check = new DefaultCheck(config);
|
|
||||||
server.createContext("/", new HttpServerHandler(check));
|
|
||||||
server.createContext("/health", new HealthHandler(config));
|
|
||||||
server.setExecutor(Executors.newFixedThreadPool(this.threadCount));
|
|
||||||
server.start();
|
|
||||||
log.info("Server unter Port {} ist erfolgreich gestartet", this.port);
|
|
||||||
} catch (final IOException e) {
|
|
||||||
log.error("Fehler beim HttpServer erstellen: {}", e.getMessage(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
69
src/main/java/de/kosit/validationtool/cmd/DemoBuilder.java
Normal file
69
src/main/java/de/kosit/validationtool/cmd/DemoBuilder.java
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
package de.kosit.validationtool.cmd;
|
||||||
|
|
||||||
|
import static de.kosit.validationtool.config.ConfigurationBuilder.defaultFallback;
|
||||||
|
import static de.kosit.validationtool.config.ConfigurationBuilder.report;
|
||||||
|
import static de.kosit.validationtool.config.ConfigurationBuilder.scenario;
|
||||||
|
import static de.kosit.validationtool.config.ConfigurationBuilder.schema;
|
||||||
|
import static de.kosit.validationtool.config.ConfigurationBuilder.schematron;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
|
||||||
|
import javax.xml.validation.Schema;
|
||||||
|
|
||||||
|
import de.kosit.validationtool.api.Configuration;
|
||||||
|
import de.kosit.validationtool.config.FallbackBuilder;
|
||||||
|
import de.kosit.validationtool.config.ScenarioBuilder;
|
||||||
|
import de.kosit.validationtool.impl.ResolvingMode;
|
||||||
|
|
||||||
|
import net.sf.saxon.s9api.XPathExecutable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Andreas Penski
|
||||||
|
*/
|
||||||
|
public class DemoBuilder {
|
||||||
|
|
||||||
|
public static void main(final String[] args) {
|
||||||
|
final XPathExecutable xpath = null;
|
||||||
|
// @formatter:off
|
||||||
|
Configuration
|
||||||
|
.create()
|
||||||
|
.name("some config")
|
||||||
|
.resolvingMode(ResolvingMode.JDK_SUPPORTED)
|
||||||
|
.with(scenario("s1").match("//name").validate(schema("http://some.schema.url")).description("some desc"))
|
||||||
|
.with(scenario("s2")
|
||||||
|
.match(xpath)
|
||||||
|
.acceptWith(xpath)
|
||||||
|
.validate(schema(URI.create("http://some.other.schema.url")))
|
||||||
|
.validate(schematron("some checks").source("some-schematron.xsl"))
|
||||||
|
.with(report("myReport").source(URI.create("some.xsl")))
|
||||||
|
.description("some desc"))
|
||||||
|
.with(defaultFallback())
|
||||||
|
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Configuration
|
||||||
|
.create()
|
||||||
|
.name("xrechnung")
|
||||||
|
.resolvingMode(ResolvingMode.STRICT_LOCAL)
|
||||||
|
.with( ubl() )
|
||||||
|
.with(cii())
|
||||||
|
.with( myFallback())
|
||||||
|
.build();
|
||||||
|
// @formatter:on
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ScenarioBuilder cii() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static FallbackBuilder myFallback() {
|
||||||
|
return new FallbackBuilder();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ScenarioBuilder ubl() {
|
||||||
|
final Schema schema = null; // load somehow
|
||||||
|
final ScenarioBuilder ubl = scenario("ubl");
|
||||||
|
ubl.validate(schema("someSchema", schema));
|
||||||
|
return ubl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -24,10 +24,10 @@ import java.nio.file.Path;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import de.kosit.validationtool.impl.ContentRepository;
|
|
||||||
import de.kosit.validationtool.impl.HtmlExtractor;
|
import de.kosit.validationtool.impl.HtmlExtractor;
|
||||||
import de.kosit.validationtool.impl.tasks.CheckAction;
|
import de.kosit.validationtool.impl.tasks.CheckAction;
|
||||||
|
|
||||||
|
import net.sf.saxon.s9api.Processor;
|
||||||
import net.sf.saxon.s9api.QName;
|
import net.sf.saxon.s9api.QName;
|
||||||
import net.sf.saxon.s9api.SaxonApiException;
|
import net.sf.saxon.s9api.SaxonApiException;
|
||||||
import net.sf.saxon.s9api.Serializer;
|
import net.sf.saxon.s9api.Serializer;
|
||||||
|
|
@ -49,12 +49,12 @@ class ExtractHtmlContentAction implements CheckAction {
|
||||||
|
|
||||||
private HtmlExtractor htmlExtraction;
|
private HtmlExtractor htmlExtraction;
|
||||||
|
|
||||||
private ContentRepository repository;
|
private Processor processor;
|
||||||
|
|
||||||
public ExtractHtmlContentAction(final ContentRepository repository, final Path outputDirectory) {
|
public ExtractHtmlContentAction(final Processor p, final Path outputDirectory) {
|
||||||
this.outputDirectory = outputDirectory;
|
this.outputDirectory = outputDirectory;
|
||||||
this.htmlExtraction = new HtmlExtractor(repository);
|
this.htmlExtraction = new HtmlExtractor(p);
|
||||||
this.repository = repository;
|
this.processor = p;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -66,7 +66,7 @@ class ExtractHtmlContentAction implements CheckAction {
|
||||||
final XdmNode node = (XdmNode) xdmItem;
|
final XdmNode node = (XdmNode) xdmItem;
|
||||||
final String name = origName + "-" + node.getAttributeValue(NAME_ATTRIBUTE);
|
final String name = origName + "-" + node.getAttributeValue(NAME_ATTRIBUTE);
|
||||||
final Path file = this.outputDirectory.resolve(name + ".html");
|
final Path file = this.outputDirectory.resolve(name + ".html");
|
||||||
final Serializer serializer = this.repository.getProcessor().newSerializer(file.toFile());
|
final Serializer serializer = this.processor.newSerializer(file.toFile());
|
||||||
try {
|
try {
|
||||||
log.info("Writing report html '{}' to {}", name, file.toAbsolutePath());
|
log.info("Writing report html '{}' to {}", name, file.toAbsolutePath());
|
||||||
serializer.serializeNode(node);
|
serializer.serializeNode(node);
|
||||||
|
|
|
||||||
|
|
@ -1,109 +0,0 @@
|
||||||
package de.kosit.validationtool.cmd;
|
|
||||||
|
|
||||||
import javax.xml.parsers.DocumentBuilder;
|
|
||||||
|
|
||||||
import org.w3c.dom.Document;
|
|
||||||
import org.w3c.dom.Element;
|
|
||||||
import org.w3c.dom.Node;
|
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
|
|
||||||
import de.kosit.validationtool.api.Configuration;
|
|
||||||
import de.kosit.validationtool.impl.ObjectFactory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Klasse zur Erzeugung Health Xml , die optiamle Status.
|
|
||||||
*
|
|
||||||
* @author Roula Antoun
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
class Health {
|
|
||||||
|
|
||||||
private final long freeMemory;
|
|
||||||
|
|
||||||
private final long maxMemory;
|
|
||||||
|
|
||||||
private final long totalMemory;
|
|
||||||
|
|
||||||
private final Configuration config;
|
|
||||||
|
|
||||||
Health(final Configuration config) {
|
|
||||||
|
|
||||||
final Runtime runtime = Runtime.getRuntime();
|
|
||||||
this.freeMemory = runtime.freeMemory();
|
|
||||||
this.maxMemory = runtime.maxMemory();
|
|
||||||
this.totalMemory = runtime.totalMemory();
|
|
||||||
this.config = config;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Methode, die schreibt das Health Xml für optimale Status
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
Document writeHealthXml() {
|
|
||||||
final DocumentBuilder dBuilder = ObjectFactory.createDocumentBuilder(false);
|
|
||||||
final Document doc = dBuilder.newDocument();
|
|
||||||
final Element rootElement = doc.createElementNS("https://localhost:8080/Health", "Health");
|
|
||||||
doc.appendChild(rootElement);
|
|
||||||
rootElement.appendChild(getMemory(doc, this.freeMemory, this.maxMemory, this.totalMemory));
|
|
||||||
rootElement.appendChild(getState(doc));
|
|
||||||
rootElement.appendChild(getScenario(doc, this.config));
|
|
||||||
return doc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Methode, die schreibt das System Status Node im Xml File
|
|
||||||
*
|
|
||||||
* @param doc Vom Typ Dokument.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
private static Node getState(final Document doc) {
|
|
||||||
final Element state = doc.createElement("state");
|
|
||||||
state.setAttribute("indicator", "OK");
|
|
||||||
final Element stateNode = doc.createElement("message");
|
|
||||||
stateNode.appendChild(doc.createTextNode("System is up and running normally"));
|
|
||||||
state.appendChild(stateNode);
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Methode, die schreibt das Scnarios Information Node im Xml File
|
|
||||||
*
|
|
||||||
* @param doc Vom Typ Dokument .
|
|
||||||
* @param config Vom Typ {@link Configuration} das verwendete scenario.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
private static Node getScenario(final Document doc, final Configuration config) {
|
|
||||||
final Element scenario = doc.createElement("scenario");
|
|
||||||
final Element scenarioNameNode = doc.createElement("name");
|
|
||||||
scenarioNameNode.appendChild(doc.createTextNode(config.getName()));
|
|
||||||
scenario.appendChild(scenarioNameNode);
|
|
||||||
return scenario;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Methode, die schreibt das Scnarios Information Node im Xml File
|
|
||||||
*
|
|
||||||
* @param doc Vom Typ Dokument .
|
|
||||||
* @param freeMemory Vom Typ long , der freier Speicher.
|
|
||||||
* @param maxMemory Vom Typ long , der maximaler Speicher
|
|
||||||
* @param totalMemory Vom Typ long , der Gesamte speicher.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
private static Node getMemory(final Document doc, final long freeMemory, final long maxMemory, final long totalMemory) {
|
|
||||||
final Element memory = doc.createElement("memoryState");
|
|
||||||
final String freeM = Long.toString(freeMemory);
|
|
||||||
final Element freeMNode = doc.createElement("freeMemory");
|
|
||||||
freeMNode.appendChild(doc.createTextNode(freeM));
|
|
||||||
memory.appendChild(freeMNode);
|
|
||||||
final String maxM = Long.toString(maxMemory);
|
|
||||||
final Element maxMNode = doc.createElement("maxMemory");
|
|
||||||
maxMNode.appendChild(doc.createTextNode(maxM));
|
|
||||||
memory.appendChild(maxMNode);
|
|
||||||
final String totalM = Long.toString(totalMemory);
|
|
||||||
final Element totalMNode = doc.createElement("totalMemory");
|
|
||||||
totalMNode.appendChild(doc.createTextNode(totalM));
|
|
||||||
memory.appendChild(totalMNode);
|
|
||||||
return memory;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -21,7 +21,7 @@ package de.kosit.validationtool.cmd;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import de.kosit.validationtool.api.CheckConfiguration;
|
import de.kosit.validationtool.api.Configuration;
|
||||||
import de.kosit.validationtool.api.Input;
|
import de.kosit.validationtool.api.Input;
|
||||||
import de.kosit.validationtool.api.Result;
|
import de.kosit.validationtool.api.Result;
|
||||||
import de.kosit.validationtool.impl.DefaultCheck;
|
import de.kosit.validationtool.impl.DefaultCheck;
|
||||||
|
|
@ -45,7 +45,7 @@ class InternalCheck extends DefaultCheck {
|
||||||
*
|
*
|
||||||
* @param configuration die Konfiguration
|
* @param configuration die Konfiguration
|
||||||
*/
|
*/
|
||||||
InternalCheck(final CheckConfiguration configuration) {
|
InternalCheck(final Configuration configuration) {
|
||||||
super(configuration);
|
super(configuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,11 +21,12 @@ package de.kosit.validationtool.cmd;
|
||||||
|
|
||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import de.kosit.validationtool.impl.ObjectFactory;
|
|
||||||
import de.kosit.validationtool.impl.tasks.CheckAction;
|
import de.kosit.validationtool.impl.tasks.CheckAction;
|
||||||
|
|
||||||
|
import net.sf.saxon.s9api.Processor;
|
||||||
import net.sf.saxon.s9api.SaxonApiException;
|
import net.sf.saxon.s9api.SaxonApiException;
|
||||||
import net.sf.saxon.s9api.Serializer;
|
import net.sf.saxon.s9api.Serializer;
|
||||||
|
|
||||||
|
|
@ -35,13 +36,16 @@ import net.sf.saxon.s9api.Serializer;
|
||||||
* @author Andreas Penski
|
* @author Andreas Penski
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
|
@RequiredArgsConstructor
|
||||||
class PrintReportAction implements CheckAction {
|
class PrintReportAction implements CheckAction {
|
||||||
|
|
||||||
|
private final Processor processor;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void check(Bag results) {
|
public void check(Bag results) {
|
||||||
try {
|
try {
|
||||||
final StringWriter writer = new StringWriter();
|
final StringWriter writer = new StringWriter();
|
||||||
final Serializer serializer = ObjectFactory.createProcessor().newSerializer(writer);
|
final Serializer serializer = processor.newSerializer(writer);
|
||||||
serializer.serializeNode(results.getReport());
|
serializer.serializeNode(results.getReport());
|
||||||
System.out.print(writer.toString());
|
System.out.print(writer.toString());
|
||||||
} catch (SaxonApiException e) {
|
} catch (SaxonApiException e) {
|
||||||
|
|
|
||||||
|
|
@ -24,9 +24,9 @@ import java.nio.file.Path;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import de.kosit.validationtool.impl.ObjectFactory;
|
|
||||||
import de.kosit.validationtool.impl.tasks.CheckAction;
|
import de.kosit.validationtool.impl.tasks.CheckAction;
|
||||||
|
|
||||||
|
import net.sf.saxon.s9api.Processor;
|
||||||
import net.sf.saxon.s9api.SaxonApiException;
|
import net.sf.saxon.s9api.SaxonApiException;
|
||||||
import net.sf.saxon.s9api.Serializer;
|
import net.sf.saxon.s9api.Serializer;
|
||||||
|
|
||||||
|
|
@ -41,12 +41,14 @@ class SerializeReportAction implements CheckAction {
|
||||||
|
|
||||||
private final Path outputDirectory;
|
private final Path outputDirectory;
|
||||||
|
|
||||||
|
private final Processor processor;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void check(Bag results) {
|
public void check(Bag results) {
|
||||||
final Path file = outputDirectory.resolve(results.getName() + "-report.xml");
|
final Path file = outputDirectory.resolve(results.getName() + "-report.xml");
|
||||||
try {
|
try {
|
||||||
log.info("Serializing result to {}", file.toAbsolutePath());
|
log.info("Serializing result to {}", file.toAbsolutePath());
|
||||||
final Serializer serializer = ObjectFactory.createProcessor().newSerializer(file.toFile());
|
final Serializer serializer = processor.newSerializer(file.toFile());
|
||||||
serializer.serializeNode(results.getReport());
|
serializer.serializeNode(results.getReport());
|
||||||
} catch (SaxonApiException e) {
|
} catch (SaxonApiException e) {
|
||||||
log.error("Can not serialize result report to {}", file.toAbsolutePath(), e);
|
log.error("Can not serialize result report to {}", file.toAbsolutePath(), e);
|
||||||
|
|
|
||||||
|
|
@ -1,92 +0,0 @@
|
||||||
package de.kosit.validationtool.config;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.Setter;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
|
|
||||||
import de.kosit.validationtool.api.Configuration;
|
|
||||||
import de.kosit.validationtool.impl.ObjectFactory;
|
|
||||||
import de.kosit.validationtool.impl.Scenario;
|
|
||||||
|
|
||||||
import net.sf.saxon.s9api.Processor;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base configuration class.
|
|
||||||
*
|
|
||||||
* @author Andreas Penski
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
public abstract class BaseConfiguration implements Configuration {
|
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
protected static class RuntimeArtefacts {
|
|
||||||
|
|
||||||
private final List<Scenario> scenarios;
|
|
||||||
|
|
||||||
private final Scenario fallbackScenario;
|
|
||||||
|
|
||||||
private String name;
|
|
||||||
|
|
||||||
private String author;
|
|
||||||
|
|
||||||
private String date;
|
|
||||||
}
|
|
||||||
|
|
||||||
private RuntimeArtefacts artefacts;
|
|
||||||
|
|
||||||
protected abstract RuntimeArtefacts buildArtefacts();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void build() {
|
|
||||||
if (this.artefacts != null) {
|
|
||||||
log.warn("Configuration already complete. Will drop previous artefacts and build again");
|
|
||||||
}
|
|
||||||
this.artefacts = buildArtefacts();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<Scenario> getScenarios() {
|
|
||||||
assertBuild();
|
|
||||||
return this.artefacts.getScenarios();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Scenario getFallbackScenario() {
|
|
||||||
assertBuild();
|
|
||||||
return this.artefacts.getFallbackScenario();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void assertBuild() {
|
|
||||||
if (this.artefacts == null) {
|
|
||||||
throw new IllegalStateException("Configuration");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Processor getProcessor() {
|
|
||||||
return ObjectFactory.createProcessor();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getAuthor() {
|
|
||||||
assertBuild();
|
|
||||||
return this.artefacts.getAuthor();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getName() {
|
|
||||||
assertBuild();
|
|
||||||
return this.artefacts.getName();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getDate() {
|
|
||||||
assertBuild();
|
|
||||||
return this.artefacts.getDate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
12
src/main/java/de/kosit/validationtool/config/Builder.java
Normal file
12
src/main/java/de/kosit/validationtool/config/Builder.java
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
package de.kosit.validationtool.config;
|
||||||
|
|
||||||
|
import de.kosit.validationtool.impl.ContentRepository;
|
||||||
|
import de.kosit.validationtool.impl.model.Result;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Andreas Penski
|
||||||
|
*/
|
||||||
|
public interface Builder<T> {
|
||||||
|
|
||||||
|
Result<T, String> build(ContentRepository repository);
|
||||||
|
}
|
||||||
|
|
@ -1,10 +1,245 @@
|
||||||
package de.kosit.validationtool.config;
|
package de.kosit.validationtool.config;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import javax.xml.validation.Schema;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.NotImplementedException;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import de.kosit.validationtool.api.Configuration;
|
||||||
|
import de.kosit.validationtool.api.ResolvingConfigurationStrategy;
|
||||||
|
import de.kosit.validationtool.impl.ContentRepository;
|
||||||
|
import de.kosit.validationtool.impl.ResolvingMode;
|
||||||
|
import de.kosit.validationtool.impl.Scenario;
|
||||||
|
import de.kosit.validationtool.impl.model.Result;
|
||||||
|
|
||||||
|
import net.sf.saxon.s9api.Processor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Implements a builder style creation of a {@link Configuration}.
|
||||||
|
*
|
||||||
* @author Andreas Penski
|
* @author Andreas Penski
|
||||||
*/
|
*/
|
||||||
|
@Slf4j
|
||||||
public class ConfigurationBuilder {
|
public class ConfigurationBuilder {
|
||||||
|
|
||||||
private ScenarioBuilder scenarioBuilder;
|
private final List<ScenarioBuilder> scenarios = new ArrayList<>();
|
||||||
|
|
||||||
|
private FallbackBuilder fallbackBuilder;
|
||||||
|
|
||||||
|
private ResolvingConfigurationStrategy resolvingConfigurationStrategy;
|
||||||
|
|
||||||
|
private ResolvingMode resolvingMode = ResolvingMode.STRICT_RELATIVE;
|
||||||
|
|
||||||
|
private Processor processor;
|
||||||
|
|
||||||
|
private String author = "API";
|
||||||
|
|
||||||
|
private String date = LocalDate.now().toString();
|
||||||
|
|
||||||
|
private String name = "Custom";
|
||||||
|
|
||||||
|
private final Map<String, Object> parameters = new HashMap<>();
|
||||||
|
|
||||||
|
private URI repository;
|
||||||
|
|
||||||
|
public ConfigurationBuilder author(final String authorName) {
|
||||||
|
this.author = authorName;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConfigurationBuilder date(final LocalDate localDate) {
|
||||||
|
this.date = localDate.toString();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConfigurationBuilder name(final String name) {
|
||||||
|
this.name = name;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConfigurationBuilder date(final Date date) {
|
||||||
|
return date(LocalDate.ofEpochDay(date.getTime()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConfigurationBuilder with(final ScenarioBuilder scenarioBuilder) {
|
||||||
|
this.scenarios.add(scenarioBuilder);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConfigurationBuilder with(final FallbackBuilder builder) {
|
||||||
|
if (this.fallbackBuilder != null) {
|
||||||
|
log.warn("Overriding previously created fallback scenario");
|
||||||
|
}
|
||||||
|
this.fallbackBuilder = builder;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a fallback scenario configuration.
|
||||||
|
*
|
||||||
|
* @return the builder
|
||||||
|
*/
|
||||||
|
public static FallbackBuilder fallback() {
|
||||||
|
return new FallbackBuilder();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the default fallback configuration if new scenario match. Note: this is public for explicit usage. If no
|
||||||
|
* fallback is configured, this is the still default fallback.
|
||||||
|
*
|
||||||
|
* @return a fallback configuration
|
||||||
|
*/
|
||||||
|
public static FallbackBuilder defaultFallback() {
|
||||||
|
throw new NotImplementedException("Not yet defined");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SchematronBuilder schematron(final String name) {
|
||||||
|
return new SchematronBuilder().name(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new schema validation configuration.
|
||||||
|
*
|
||||||
|
* @return a configuration builder for schema
|
||||||
|
*/
|
||||||
|
public static SchemaBuilder schema() {
|
||||||
|
return new SchemaBuilder();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new schema validation configuration.
|
||||||
|
*
|
||||||
|
* @param name the name of the schema
|
||||||
|
* @param schema the actual precompiled schema to use
|
||||||
|
* @return a configuration builder for schema
|
||||||
|
*/
|
||||||
|
public static SchemaBuilder schema(final String name, final Schema schema) {
|
||||||
|
return new SchemaBuilder().name(name).schema(schema);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new schema validation configuration.
|
||||||
|
*
|
||||||
|
* @param name the name of the schema
|
||||||
|
* @return a configuration builder for schema
|
||||||
|
*/
|
||||||
|
public static SchemaBuilder schema(final String name) {
|
||||||
|
return new SchemaBuilder().name(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new schema validation configuration.
|
||||||
|
*
|
||||||
|
* @param uri the uri location of the schema
|
||||||
|
* @return a configuration builder for schema
|
||||||
|
*/
|
||||||
|
public static SchemaBuilder schema(final URI uri) {
|
||||||
|
return new SchemaBuilder().schemaLocation(uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new named scenario configuration.
|
||||||
|
*
|
||||||
|
* @param name the name of the scenario
|
||||||
|
* @return the scenario configuration builder
|
||||||
|
*/
|
||||||
|
public static ScenarioBuilder scenario(final String name) {
|
||||||
|
return new ScenarioBuilder(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create named report configuration.
|
||||||
|
*
|
||||||
|
* @param name the name of the report
|
||||||
|
* @return the report configuration builder
|
||||||
|
*/
|
||||||
|
public static ReportBuilder report(final String name) {
|
||||||
|
return new ReportBuilder().name(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Configuration build() {
|
||||||
|
final ResolvingConfigurationStrategy resolving = getResolvingConfigurationStrategy();
|
||||||
|
if (this.processor == null) {
|
||||||
|
this.processor = resolving.createProcessor();
|
||||||
|
}
|
||||||
|
final ContentRepository contentRepository = new ContentRepository(this.processor, this.repository,
|
||||||
|
resolving.createResolver(this.repository));
|
||||||
|
contentRepository.setSchemaFactory(resolving.createSchemaFactory());
|
||||||
|
contentRepository.setResolvingConfigurationStrategy(resolving);
|
||||||
|
|
||||||
|
final List<Scenario> list = initializeScenarios(contentRepository);
|
||||||
|
final Scenario fallbackScenario = initializeFallback(contentRepository);
|
||||||
|
final DefaultConfiguration configuration = new DefaultConfiguration(list, fallbackScenario);
|
||||||
|
configuration.setAdditionalParameters(this.parameters);
|
||||||
|
configuration.setAuthor(this.author);
|
||||||
|
configuration.setDate(this.date);
|
||||||
|
configuration.setName(this.name);
|
||||||
|
configuration.setContentRepository(contentRepository);
|
||||||
|
return (configuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Scenario initializeFallback(final ContentRepository contentRepository) {
|
||||||
|
if (this.fallbackBuilder == null) {
|
||||||
|
throw new IllegalStateException("No fallback configuration specified");
|
||||||
|
}
|
||||||
|
final Result<Scenario, String> result = this.fallbackBuilder.build(contentRepository);
|
||||||
|
if (result.isInvalid()) {
|
||||||
|
throw new IllegalStateException("Invalid fallback configuration: " + String.join(",", result.getErrors()));
|
||||||
|
}
|
||||||
|
return result.getObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Scenario> initializeScenarios(final ContentRepository contentRepository) {
|
||||||
|
if (this.scenarios.size() == 0) {
|
||||||
|
throw new IllegalStateException("No scenario specified");
|
||||||
|
}
|
||||||
|
return this.scenarios.stream().map(s -> {
|
||||||
|
final Result<Scenario, String> result = s.build(contentRepository);
|
||||||
|
if (result.isInvalid()) {
|
||||||
|
final String msg = String.join(",", result.getErrors());
|
||||||
|
throw new IllegalStateException(String.format("Invalid configuration for scenario %s found: %s", s.getName(), msg));
|
||||||
|
}
|
||||||
|
return result.getObject();
|
||||||
|
}).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
private ResolvingConfigurationStrategy getResolvingConfigurationStrategy() {
|
||||||
|
if (this.resolvingConfigurationStrategy != null) {
|
||||||
|
log.info("Custom resolving strategy supplied. Please take care of xml security!");
|
||||||
|
return this.resolvingConfigurationStrategy;
|
||||||
|
}
|
||||||
|
log.info("Using resolving strategy {}", this.resolvingMode);
|
||||||
|
return this.resolvingMode.getStrategy();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConfigurationBuilder resolvingMode(final ResolvingMode mode) {
|
||||||
|
this.resolvingMode = mode;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a specific strategy to use for resolving artefacts for scenarios.
|
||||||
|
*
|
||||||
|
* @param strategy the strategy
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public ConfigurationBuilder resolvingStrategy(final ResolvingConfigurationStrategy strategy) {
|
||||||
|
this.resolvingConfigurationStrategy = strategy;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConfigurationBuilder useRepository(final URI repository) {
|
||||||
|
this.repository = repository;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,28 +4,36 @@ import static org.apache.commons.lang3.StringUtils.startsWith;
|
||||||
|
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import javax.xml.validation.Schema;
|
||||||
|
|
||||||
import lombok.AccessLevel;
|
import lombok.AccessLevel;
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import de.kosit.validationtool.api.Check;
|
import de.kosit.validationtool.api.Check;
|
||||||
|
import de.kosit.validationtool.api.Configuration;
|
||||||
import de.kosit.validationtool.api.InputFactory;
|
import de.kosit.validationtool.api.InputFactory;
|
||||||
|
import de.kosit.validationtool.api.ResolvingConfigurationStrategy;
|
||||||
import de.kosit.validationtool.impl.CollectingErrorEventHandler;
|
import de.kosit.validationtool.impl.CollectingErrorEventHandler;
|
||||||
import de.kosit.validationtool.impl.ContentRepository;
|
import de.kosit.validationtool.impl.ContentRepository;
|
||||||
import de.kosit.validationtool.impl.ConversionService;
|
import de.kosit.validationtool.impl.ConversionService;
|
||||||
import de.kosit.validationtool.impl.RelativeUriResolver;
|
import de.kosit.validationtool.impl.ResolvingMode;
|
||||||
import de.kosit.validationtool.impl.Scenario;
|
import de.kosit.validationtool.impl.Scenario;
|
||||||
import de.kosit.validationtool.impl.model.Result;
|
import de.kosit.validationtool.impl.model.Result;
|
||||||
import de.kosit.validationtool.impl.tasks.DocumentParseAction;
|
import de.kosit.validationtool.impl.tasks.DocumentParseAction;
|
||||||
|
import de.kosit.validationtool.impl.xml.RelativeUriResolver;
|
||||||
import de.kosit.validationtool.model.reportInput.XMLSyntaxError;
|
import de.kosit.validationtool.model.reportInput.XMLSyntaxError;
|
||||||
import de.kosit.validationtool.model.scenarios.CreateReportType;
|
import de.kosit.validationtool.model.scenarios.ResourceType;
|
||||||
import de.kosit.validationtool.model.scenarios.ScenarioType;
|
import de.kosit.validationtool.model.scenarios.ScenarioType;
|
||||||
import de.kosit.validationtool.model.scenarios.Scenarios;
|
import de.kosit.validationtool.model.scenarios.Scenarios;
|
||||||
|
|
||||||
|
import net.sf.saxon.s9api.Processor;
|
||||||
import net.sf.saxon.s9api.QName;
|
import net.sf.saxon.s9api.QName;
|
||||||
import net.sf.saxon.s9api.XdmNode;
|
import net.sf.saxon.s9api.XdmNode;
|
||||||
import net.sf.saxon.s9api.XdmNodeKind;
|
import net.sf.saxon.s9api.XdmNodeKind;
|
||||||
|
|
@ -36,9 +44,9 @@ import net.sf.saxon.s9api.XdmNodeKind;
|
||||||
*
|
*
|
||||||
* @author Andreas Penski
|
* @author Andreas Penski
|
||||||
*/
|
*/
|
||||||
@AllArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class LoadConfiguration extends BaseConfiguration {
|
public class ConfigurationLoader {
|
||||||
|
|
||||||
private static final String SUPPORTED_MAJOR_VERSION = "1";
|
private static final String SUPPORTED_MAJOR_VERSION = "1";
|
||||||
|
|
||||||
|
|
@ -55,6 +63,12 @@ public class LoadConfiguration extends BaseConfiguration {
|
||||||
*/
|
*/
|
||||||
private final URI scenarioRepository;
|
private final URI scenarioRepository;
|
||||||
|
|
||||||
|
protected ResolvingMode resolvingMode = ResolvingMode.STRICT_RELATIVE;
|
||||||
|
|
||||||
|
protected ResolvingConfigurationStrategy resolvingConfigurationStrategy;
|
||||||
|
|
||||||
|
protected final Map<String, Object> parameters = new HashMap<>();
|
||||||
|
|
||||||
URI getScenarioRepository() {
|
URI getScenarioRepository() {
|
||||||
if (this.scenarioRepository == null) {
|
if (this.scenarioRepository == null) {
|
||||||
log.info("Creating default scenario repository (alongside scenario definition)");
|
log.info("Creating default scenario repository (alongside scenario definition)");
|
||||||
|
|
@ -63,9 +77,10 @@ public class LoadConfiguration extends BaseConfiguration {
|
||||||
return this.scenarioRepository;
|
return this.scenarioRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void checkVersion(final URI scenarioDefinition) {
|
private static void checkVersion(final URI scenarioDefinition, final Processor processor) {
|
||||||
try {
|
try {
|
||||||
final Result<XdmNode, XMLSyntaxError> result = DocumentParseAction.parseDocument(InputFactory.read(scenarioDefinition.toURL()));
|
final Result<XdmNode, XMLSyntaxError> result = new DocumentParseAction(processor)
|
||||||
|
.parseDocument(InputFactory.read(scenarioDefinition.toURL()));
|
||||||
if (result.isValid() && !isSupportedDocument(result.getObject())) {
|
if (result.isValid() && !isSupportedDocument(result.getObject())) {
|
||||||
throw new IllegalStateException(String.format(
|
throw new IllegalStateException(String.format(
|
||||||
"Specified scenario configuration %s is not supported.%nThis version only supports definitions of '%s'",
|
"Specified scenario configuration %s is not supported.%nThis version only supports definitions of '%s'",
|
||||||
|
|
@ -94,54 +109,53 @@ public class LoadConfiguration extends BaseConfiguration {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Scenario createFallback(final Scenarios scenarios, final ContentRepository repository) {
|
private static Scenario createFallback(final Scenarios scenarios, final ContentRepository repository) {
|
||||||
final ScenarioType t = new ScenarioType();
|
final ResourceType noscenarioResource = scenarios.getNoScenarioReport().getResource();
|
||||||
t.setName("Fallback-Scenario");
|
return new FallbackBuilder().source(noscenarioResource.getLocation()).name(noscenarioResource.getName()).build(repository)
|
||||||
t.setMatch("count(/)<0");
|
.getObject();
|
||||||
final CreateReportType reportType = new CreateReportType();
|
|
||||||
reportType.setResource(scenarios.getNoScenarioReport().getResource());
|
|
||||||
// always reject
|
|
||||||
t.setAcceptMatch("count(/)<0");
|
|
||||||
t.setCreateReport(reportType);
|
|
||||||
final Scenario sceanrio = initialize(t, repository);
|
|
||||||
sceanrio.setFallback(true);
|
|
||||||
return sceanrio;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public Configuration build() {
|
||||||
protected RuntimeArtefacts buildArtefacts() {
|
final ResolvingConfigurationStrategy resolving = getResolvingConfigurationStrategy();
|
||||||
final ContentRepository contentRepository = buildContentRepository();
|
final Processor processor = resolving.createProcessor();
|
||||||
final Scenarios def = loadScenarios();
|
final ContentRepository contentRepository = new ContentRepository(processor, getScenarioRepository(),
|
||||||
|
resolving.createResolver(this.getScenarioRepository()));
|
||||||
|
contentRepository.setSchemaFactory(resolving.createSchemaFactory());
|
||||||
|
contentRepository.setResolvingConfigurationStrategy(resolving);
|
||||||
|
|
||||||
|
final Scenarios def = loadScenarios(contentRepository.getScenarioSchema(), processor);
|
||||||
final List<Scenario> scenarios = initializeScenarios(def, contentRepository);
|
final List<Scenario> scenarios = initializeScenarios(def, contentRepository);
|
||||||
final Scenario fallbackScenario = createFallback(def, contentRepository);
|
final Scenario fallbackScenario = createFallback(def, contentRepository);
|
||||||
final RuntimeArtefacts runtimeArtefacts = new RuntimeArtefacts(scenarios, fallbackScenario);
|
final DefaultConfiguration configuration = new DefaultConfiguration(scenarios, fallbackScenario);
|
||||||
runtimeArtefacts.setAuthor(def.getAuthor());
|
configuration.setAdditionalParameters(this.parameters);
|
||||||
runtimeArtefacts.setDate(def.getDate().toString());
|
configuration.setAuthor(def.getAuthor());
|
||||||
runtimeArtefacts.setName(def.getName());
|
configuration.setDate(def.getDate().toString());
|
||||||
return runtimeArtefacts;
|
configuration.setName(def.getName());
|
||||||
|
configuration.setContentRepository(contentRepository);
|
||||||
|
return (configuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<Scenario> initializeScenarios(final Scenarios def, final ContentRepository contentRepository) {
|
private static List<Scenario> initializeScenarios(final Scenarios def, final ContentRepository contentRepository) {
|
||||||
return def.getScenario().stream().map(s -> initialize(s, contentRepository)).collect(Collectors.toList());
|
return def.getScenario().stream().map(s -> initialize(s, contentRepository)).collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
private ContentRepository buildContentRepository() {
|
private ResolvingConfigurationStrategy getResolvingConfigurationStrategy() {
|
||||||
return new ContentRepository(getProcessor(), getScenarioRepository());
|
if (this.resolvingConfigurationStrategy != null) {
|
||||||
|
log.info("Custom resolving strategy supplied. Please take care of xml security!");
|
||||||
|
return this.resolvingConfigurationStrategy;
|
||||||
|
}
|
||||||
|
log.info("Using resolving strategy {}", this.resolvingMode);
|
||||||
|
return this.resolvingMode.getStrategy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private Scenarios loadScenarios(final Schema scenarioSchema, final Processor processor) {
|
||||||
public ContentRepository getContentRepository() {
|
|
||||||
return buildContentRepository();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Scenarios loadScenarios() {
|
|
||||||
final ConversionService conversionService = new ConversionService();
|
final ConversionService conversionService = new ConversionService();
|
||||||
checkVersion(this.scenarioDefinition);
|
checkVersion(this.scenarioDefinition, processor);
|
||||||
log.info("Loading scenarios from {}", this.scenarioDefinition);
|
log.info("Loading scenarios from {}", this.scenarioDefinition);
|
||||||
final CollectingErrorEventHandler handler = new CollectingErrorEventHandler();
|
final CollectingErrorEventHandler handler = new CollectingErrorEventHandler();
|
||||||
final Scenarios scenarios = conversionService.readXml(this.scenarioDefinition, Scenarios.class,
|
final Scenarios scenarios = conversionService.readXml(this.scenarioDefinition, Scenarios.class, scenarioSchema, handler);
|
||||||
getContentRepository().getScenarioSchema(), handler);
|
|
||||||
if (!handler.hasErrors()) {
|
if (!handler.hasErrors()) {
|
||||||
log.info("Loading scenario content from {}", this.scenarioRepository);
|
log.info("Loading scenario content from {}", this.getScenarioRepository());
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalStateException(
|
throw new IllegalStateException(
|
||||||
String.format("Can not load scenarios from %s due to %s", getScenarioDefinition(), handler.getErrorDescription()));
|
String.format("Can not load scenarios from %s due to %s", getScenarioDefinition(), handler.getErrorDescription()));
|
||||||
|
|
@ -152,27 +166,23 @@ public class LoadConfiguration extends BaseConfiguration {
|
||||||
|
|
||||||
private static Scenario initialize(final ScenarioType def, final ContentRepository repository) {
|
private static Scenario initialize(final ScenarioType def, final ContentRepository repository) {
|
||||||
final Scenario s = new Scenario(def);
|
final Scenario s = new Scenario(def);
|
||||||
s.setSchema(repository.createSchema(def));
|
|
||||||
s.setReportTransformation(repository.createReportTransformation(def));
|
|
||||||
s.setMatchExecutable(repository.createMatchExecutable(def));
|
s.setMatchExecutable(repository.createMatchExecutable(def));
|
||||||
|
s.setSchema(repository.createSchema(def));
|
||||||
|
s.setSchematronValidations(repository.createSchematronTransformations(def));
|
||||||
|
s.setReportTransformation(repository.createReportTransformation(def));
|
||||||
if (def.getAcceptMatch() != null) {
|
if (def.getAcceptMatch() != null) {
|
||||||
s.setAcceptExecutable(repository.createAccepptExecutable(def));
|
s.setAcceptExecutable(repository.createAccepptExecutable(def));
|
||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public ConfigurationLoader setResolvingMode(final ResolvingMode mode) {
|
||||||
public String getAuthor() {
|
this.resolvingMode = mode;
|
||||||
return null;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public ConfigurationLoader addParameter(final String name, final Object value) {
|
||||||
public String getName() {
|
this.parameters.put(name, value);
|
||||||
return null;
|
return this;
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getDate() {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
package de.kosit.validationtool.config;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import de.kosit.validationtool.api.Configuration;
|
||||||
|
import de.kosit.validationtool.impl.ContentRepository;
|
||||||
|
import de.kosit.validationtool.impl.Scenario;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default implementation class for {@link Configuration}. This class contains all information to run a
|
||||||
|
* {@link de.kosit.validationtool.impl.DefaultCheck}.
|
||||||
|
*
|
||||||
|
* @author Andreas Penski
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class DefaultConfiguration implements Configuration {
|
||||||
|
|
||||||
|
private final List<Scenario> scenarios;
|
||||||
|
|
||||||
|
private final Scenario fallbackScenario;
|
||||||
|
|
||||||
|
private ContentRepository contentRepository;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private String author;
|
||||||
|
|
||||||
|
private String date;
|
||||||
|
|
||||||
|
public Map<String, Object> additionalParameters;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,95 @@
|
||||||
|
package de.kosit.validationtool.config;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
|
|
||||||
|
import de.kosit.validationtool.impl.ContentRepository;
|
||||||
|
import de.kosit.validationtool.impl.Scenario;
|
||||||
|
import de.kosit.validationtool.impl.Scenario.Transformation;
|
||||||
|
import de.kosit.validationtool.impl.model.Result;
|
||||||
|
import de.kosit.validationtool.model.scenarios.CreateReportType;
|
||||||
|
import de.kosit.validationtool.model.scenarios.ScenarioType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Andreas Penski
|
||||||
|
*/
|
||||||
|
public class FallbackBuilder implements Builder<Scenario> {
|
||||||
|
|
||||||
|
private final ReportBuilder internal = new ReportBuilder().name("fallback");
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Result<Scenario, String> build(final ContentRepository repository) {
|
||||||
|
final ScenarioType object = createObject();
|
||||||
|
final Result<Pair<CreateReportType, Transformation>, String> build = this.internal.build(repository);
|
||||||
|
final Result<Scenario, String> result;
|
||||||
|
if (build.isValid()) {
|
||||||
|
object.setCreateReport(build.getObject().getLeft());
|
||||||
|
final Scenario s = new Scenario(object);
|
||||||
|
s.setFallback(true);
|
||||||
|
s.setReportTransformation(build.getObject().getRight());
|
||||||
|
result = new Result<>(s);
|
||||||
|
} else {
|
||||||
|
result = new Result<>(build.getErrors());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ScenarioType createObject() {
|
||||||
|
final ScenarioType t = new ScenarioType();
|
||||||
|
t.setName("Fallback-Scenario");
|
||||||
|
t.setMatch("count(/)<0");
|
||||||
|
// always reject
|
||||||
|
t.setAcceptMatch("count(/)<0");
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifices a source for this report. This is either used to compile the report transformation or as documentation for
|
||||||
|
* a precompiled tranformation.
|
||||||
|
*
|
||||||
|
* @param source the source
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public FallbackBuilder source(final String source) {
|
||||||
|
this.internal.source(source);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifices a source for this report. This is either used to compile the report transformation or as documentation for
|
||||||
|
* a precompiled tranformation.
|
||||||
|
*
|
||||||
|
* @param source the source
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public FallbackBuilder source(final URI source) {
|
||||||
|
this.internal.source(source);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifices a source for this report. This is either used to compile the report transformation or as documentation for
|
||||||
|
* a precompiled tranformation.
|
||||||
|
*
|
||||||
|
* @param source the source
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public FallbackBuilder source(final Path source) {
|
||||||
|
this.internal.source(source);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the name of the report source to a specific value.
|
||||||
|
*
|
||||||
|
* @param name the name
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public FallbackBuilder name(final String name) {
|
||||||
|
this.internal.name(name);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
116
src/main/java/de/kosit/validationtool/config/ReportBuilder.java
Normal file
116
src/main/java/de/kosit/validationtool/config/ReportBuilder.java
Normal file
|
|
@ -0,0 +1,116 @@
|
||||||
|
package de.kosit.validationtool.config;
|
||||||
|
|
||||||
|
import static org.apache.commons.lang3.ObjectUtils.isNotEmpty;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.tuple.ImmutablePair;
|
||||||
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import de.kosit.validationtool.impl.ContentRepository;
|
||||||
|
import de.kosit.validationtool.impl.Scenario.Transformation;
|
||||||
|
import de.kosit.validationtool.impl.model.Result;
|
||||||
|
import de.kosit.validationtool.model.scenarios.CreateReportType;
|
||||||
|
import de.kosit.validationtool.model.scenarios.ResourceType;
|
||||||
|
|
||||||
|
import net.sf.saxon.s9api.XsltExecutable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builder style configuration for the report transformation.
|
||||||
|
*
|
||||||
|
* @author Andreas Penski
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class ReportBuilder implements Builder<Pair<CreateReportType, Transformation>> {
|
||||||
|
|
||||||
|
private static final String DEFAULT_NAME = "manually created report";
|
||||||
|
|
||||||
|
private XsltExecutable executable;
|
||||||
|
|
||||||
|
private URI source;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Result<Pair<CreateReportType, Transformation>, String> build(final ContentRepository repository) {
|
||||||
|
if (this.executable == null && this.source == null) {
|
||||||
|
return createError("Must supply source location and/or executable");
|
||||||
|
}
|
||||||
|
final CreateReportType object = createObject();
|
||||||
|
Result<Pair<CreateReportType, Transformation>, String> result;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (this.executable == null) {
|
||||||
|
this.executable = repository.createTransformation(object.getResource()).getExecutable();
|
||||||
|
}
|
||||||
|
result = new Result<>(new ImmutablePair<>(object, new Transformation(this.executable, object.getResource())));
|
||||||
|
} catch (final IllegalStateException e) {
|
||||||
|
log.error(e.getMessage(), e);
|
||||||
|
result = createError(
|
||||||
|
String.format("Can not create report configuration based on %s. Exception is %s", this.source, e.getMessage()));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private CreateReportType createObject() {
|
||||||
|
final CreateReportType o = new CreateReportType();
|
||||||
|
final ResourceType r = new ResourceType();
|
||||||
|
r.setLocation(this.source.toASCIIString());
|
||||||
|
r.setName(isNotEmpty(this.name) ? this.name : DEFAULT_NAME);
|
||||||
|
o.setResource(r);
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Result<Pair<CreateReportType, Transformation>, String> createError(final String msg) {
|
||||||
|
return new Result<>(null, Collections.singletonList(msg));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifices a source for this report. This is either used to compile the report transformation or as documentation for
|
||||||
|
* a precompiled tranformation.
|
||||||
|
*
|
||||||
|
* @param source the source
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public ReportBuilder source(final String source) {
|
||||||
|
return source(URI.create(source));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifices a source for this report. This is either used to compile the report transformation or as documentation for
|
||||||
|
* a precompiled tranformation.
|
||||||
|
*
|
||||||
|
* @param source the source
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public ReportBuilder source(final URI source) {
|
||||||
|
this.source = source;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifices a source for this report. This is either used to compile the report transformation or as documentation for
|
||||||
|
* a precompiled tranformation.
|
||||||
|
*
|
||||||
|
* @param source the source
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public ReportBuilder source(final Path source) {
|
||||||
|
return source(source.toUri());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the name of the report source to a specific value.
|
||||||
|
*
|
||||||
|
* @param name the name
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public ReportBuilder name(final String name) {
|
||||||
|
this.name = name;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,72 +1,270 @@
|
||||||
package de.kosit.validationtool.config;
|
package de.kosit.validationtool.config;
|
||||||
|
|
||||||
import java.net.URL;
|
import static org.apache.commons.lang3.ObjectUtils.isNotEmpty;
|
||||||
import java.util.Collections;
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import javax.xml.validation.Schema;
|
import javax.xml.validation.Schema;
|
||||||
|
|
||||||
import org.w3c.dom.ls.LSResourceResolver;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
|
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
import de.kosit.validationtool.impl.ContentRepository;
|
import de.kosit.validationtool.impl.ContentRepository;
|
||||||
import de.kosit.validationtool.impl.ObjectFactory;
|
import de.kosit.validationtool.impl.Scenario;
|
||||||
|
import de.kosit.validationtool.impl.Scenario.Transformation;
|
||||||
|
import de.kosit.validationtool.impl.model.Result;
|
||||||
|
import de.kosit.validationtool.model.scenarios.CreateReportType;
|
||||||
|
import de.kosit.validationtool.model.scenarios.DescriptionType;
|
||||||
|
import de.kosit.validationtool.model.scenarios.NamespaceType;
|
||||||
|
import de.kosit.validationtool.model.scenarios.ObjectFactory;
|
||||||
import de.kosit.validationtool.model.scenarios.ScenarioType;
|
import de.kosit.validationtool.model.scenarios.ScenarioType;
|
||||||
|
import de.kosit.validationtool.model.scenarios.ValidateWithSchematron;
|
||||||
|
import de.kosit.validationtool.model.scenarios.ValidateWithXmlSchema;
|
||||||
|
|
||||||
import net.sf.saxon.s9api.XsltExecutable;
|
import net.sf.saxon.s9api.XPathExecutable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Builder for {@link Scenario} configuration.
|
||||||
|
*
|
||||||
* @author Andreas Penski
|
* @author Andreas Penski
|
||||||
*/
|
*/
|
||||||
public class ScenarioBuilder {
|
@RequiredArgsConstructor
|
||||||
|
public class ScenarioBuilder implements Builder<Scenario> {
|
||||||
|
|
||||||
private final ScenarioType scenario;
|
private static int nameCount = 0;
|
||||||
|
|
||||||
private final ContentRepository contentRepository = new ContentRepository(ObjectFactory.createProcessor(), null);
|
private static final String DEFAULT_DESCRIPTION = "Dieses Scenario wurde per API erstellt";
|
||||||
|
|
||||||
ScenarioBuilder(final String name) {
|
private final Map<String, String> namespaces = new HashMap<>();
|
||||||
this.scenario = new ScenarioType();
|
|
||||||
this.scenario.setName(name);
|
private final XPathBuilder matchConfig = new XPathBuilder();
|
||||||
|
|
||||||
|
private final XPathBuilder acceptConfig = new XPathBuilder();
|
||||||
|
|
||||||
|
@Getter(AccessLevel.PACKAGE)
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
private SchemaBuilder schemaBuilder;
|
||||||
|
|
||||||
|
private final List<SchematronBuilder> schematronBuilders = new ArrayList<>();
|
||||||
|
|
||||||
|
private ReportBuilder reportBuilder;
|
||||||
|
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Result<Scenario, String> build(final ContentRepository repository) {
|
||||||
|
final List<String> errors = new ArrayList<>();
|
||||||
|
final Scenario scenario = new Scenario(createType());
|
||||||
|
buildMatch(repository, errors, scenario);
|
||||||
|
buildSchema(repository, errors, scenario);
|
||||||
|
buildSchematron(repository, errors, scenario);
|
||||||
|
buildReport(repository, errors, scenario);
|
||||||
|
buildAccept(repository, errors, scenario);
|
||||||
|
buildNamespaces(scenario);
|
||||||
|
return new Result<>(scenario, errors);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ScenarioBuilder matches(final String xpath) {
|
/**
|
||||||
return matches(xpath, Collections.emptyMap());
|
* Add a preconfiguration {@link XPathExecutable} to match the scenario
|
||||||
}
|
*
|
||||||
|
* @param executable the xpath executable
|
||||||
private ScenarioBuilder matches(final String xpath, final Map<String, String> namespaces) {
|
* @return this
|
||||||
// final XPathExecutable matchExecutable = this.contentRepository.createXPath(xpath, namespaces);
|
*/
|
||||||
// this.scenario.setMatchExecutable(matchExecutable);
|
public ScenarioBuilder match(final XPathExecutable executable) {
|
||||||
// this.scenario.setMatch(xpath);
|
this.matchConfig.setExecutable(executable);
|
||||||
// if (namespaces != null) {
|
|
||||||
// this.scenario.getNamespace().addAll(namespaces.entrySet().stream().map(e -> {
|
|
||||||
// NamespaceType t = new NamespaceType();
|
|
||||||
// t.setPrefix(e.getKey());
|
|
||||||
// t.setValue(e.getValue());
|
|
||||||
// return t;
|
|
||||||
// }).collect(Collectors.toList()));
|
|
||||||
// } else {
|
|
||||||
// this.scenario.getNamespace().clear();
|
|
||||||
// }
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ScenarioBuilder schemaValidation(final Schema schema) {
|
/**
|
||||||
|
* Add an xpath expression to match the scenario. You can leverage declared namespaces.
|
||||||
|
*
|
||||||
|
* @param xpath the expression
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public ScenarioBuilder match(final String xpath) {
|
||||||
|
this.matchConfig.setXpath(xpath);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ScenarioBuilder schemaValidation(final URL url) {
|
/**
|
||||||
return schemalidation(url, null);
|
* Declare a namespace to use for match and accept configurations.
|
||||||
}
|
*
|
||||||
|
* @param prefix the prefix to use
|
||||||
private ScenarioBuilder schemalidation(final URL url, final LSResourceResolver resolver) {
|
* @param uri the uri of this namespace
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public ScenarioBuilder declareNamespace(final String prefix, final String uri) {
|
||||||
|
this.namespaces.put(prefix, uri);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ScenarioBuilder addSchematronValidation(final XsltExecutable executable) {
|
/**
|
||||||
|
* Add a preconfiguration {@link XPathExecutable} to compute acceptance for the scenario
|
||||||
|
*
|
||||||
|
* @param executable the xpath executable
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public ScenarioBuilder acceptWith(final XPathExecutable executable) {
|
||||||
|
this.acceptConfig.setExecutable(executable);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ScenarioBuilder withReportGenerator(final XsltExecutable executable) {
|
/**
|
||||||
|
* Add an xpath expression to compute acceptance for the scenario. You can leverage declared namespaces.
|
||||||
|
*
|
||||||
|
* @param acceptXpath the xpath expresison
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public ScenarioBuilder acceptWith(final String acceptXpath) {
|
||||||
|
this.acceptConfig.setXpath(acceptXpath);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a schematron validation configuration for this scenario.
|
||||||
|
*
|
||||||
|
* @param schematron the schematron configuration
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public ScenarioBuilder validate(final SchematronBuilder schematron) {
|
||||||
|
if (schematron != null) {
|
||||||
|
this.schematronBuilders.add(schematron);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate matching {@link de.kosit.validationtool.api.Input Inputs} with the specified schema configuration.
|
||||||
|
*
|
||||||
|
* @param schema the schema configuration
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public ScenarioBuilder validate(final SchemaBuilder schema) {
|
||||||
|
this.schemaBuilder = schema;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add description for this scenario. This is part of the
|
||||||
|
* {@link de.kosit.validationtool.model.reportInput.CreateReportInput} configuration and can be used while creating the
|
||||||
|
* report
|
||||||
|
*
|
||||||
|
* @param description the description
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public ScenarioBuilder description(final String description) {
|
||||||
|
this.description = description;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a configuration for generating the final report for the {@link de.kosit.validationtool.api.Input}.
|
||||||
|
*
|
||||||
|
* @param reportBuilder the report configuration
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public ScenarioBuilder with(final ReportBuilder reportBuilder) {
|
||||||
|
this.reportBuilder = reportBuilder;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String generateName() {
|
||||||
|
return "manually created scenario " + nameCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void buildNamespaces(final Scenario scenario) {
|
||||||
|
this.namespaces.putAll(this.acceptConfig.getNamespaces());
|
||||||
|
this.namespaces.putAll(this.matchConfig.getNamespaces());
|
||||||
|
final List<NamespaceType> all = this.namespaces.entrySet().stream().map(e -> {
|
||||||
|
final NamespaceType n = new NamespaceType();
|
||||||
|
n.setPrefix(e.getKey());
|
||||||
|
n.setValue(e.getValue());
|
||||||
|
return n;
|
||||||
|
}).collect(Collectors.toList());
|
||||||
|
scenario.getConfiguration().getNamespace().addAll(all);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void buildMatch(final ContentRepository repository, final List<String> errors, final Scenario scenario) {
|
||||||
|
this.matchConfig.setNamespaces(this.namespaces);
|
||||||
|
final Result<XPathExecutable, String> result = this.matchConfig.build(repository);
|
||||||
|
if (result.isValid()) {
|
||||||
|
scenario.setMatchExecutable(result.getObject());
|
||||||
|
scenario.getConfiguration().setMatch(this.matchConfig.getXPath());
|
||||||
|
this.namespaces.putAll(this.matchConfig.getNamespaces());
|
||||||
|
} else {
|
||||||
|
errors.addAll(result.getErrors());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void buildAccept(final ContentRepository repository, final List<String> errors, final Scenario scenario) {
|
||||||
|
this.acceptConfig.setNamespaces(this.namespaces);
|
||||||
|
final Result<XPathExecutable, String> result = this.acceptConfig.build(repository);
|
||||||
|
if (result.isValid()) {
|
||||||
|
scenario.setAcceptExecutable(result.getObject());
|
||||||
|
scenario.getConfiguration().setAcceptMatch(this.acceptConfig.getXPath());
|
||||||
|
this.namespaces.putAll(this.acceptConfig.getNamespaces());
|
||||||
|
} else {
|
||||||
|
errors.addAll(result.getErrors());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void buildReport(final ContentRepository repository, final List<String> errors, final Scenario scenario) {
|
||||||
|
if (this.reportBuilder == null) {
|
||||||
|
errors.add("Must supply report configuration");
|
||||||
|
} else {
|
||||||
|
final Result<Pair<CreateReportType, Transformation>, String> result = this.reportBuilder.build(repository);
|
||||||
|
if (result.isValid()) {
|
||||||
|
scenario.setReportTransformation(result.getObject().getRight());
|
||||||
|
scenario.getConfiguration().setCreateReport(result.getObject().getLeft());
|
||||||
|
} else {
|
||||||
|
errors.addAll(result.getErrors());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void buildSchematron(final ContentRepository repository, final List<String> errors, final Scenario scenario) {
|
||||||
|
this.schematronBuilders.forEach(e -> {
|
||||||
|
final Result<Pair<ValidateWithSchematron, Transformation>, String> result = e.build(repository);
|
||||||
|
if (result.isValid()) {
|
||||||
|
scenario.getConfiguration().getValidateWithSchematron().add(result.getObject().getLeft());
|
||||||
|
scenario.getSchematronValidations().add(result.getObject().getRight());
|
||||||
|
} else {
|
||||||
|
errors.addAll(result.getErrors());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void buildSchema(final ContentRepository repository, final List<String> errors, final Scenario scenario) {
|
||||||
|
if (this.schemaBuilder == null) {
|
||||||
|
errors.add("Must supply schema for validation");
|
||||||
|
} else {
|
||||||
|
final Result<Pair<ValidateWithXmlSchema, Schema>, String> result = this.schemaBuilder.build(repository);
|
||||||
|
if (result.isValid()) {
|
||||||
|
scenario.setSchema(result.getObject().getRight());
|
||||||
|
scenario.getConfiguration().setValidateWithXmlSchema(result.getObject().getLeft());
|
||||||
|
} else {
|
||||||
|
errors.addAll(result.getErrors());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ScenarioType createType() {
|
||||||
|
final ScenarioType type = new ScenarioType();
|
||||||
|
type.setName(isNotEmpty(this.name) ? this.name : generateName());
|
||||||
|
final DescriptionType desc = new DescriptionType();
|
||||||
|
desc.getPOrOlOrUl()
|
||||||
|
.add(new ObjectFactory().createDescriptionTypeP(StringUtils.defaultIfBlank(this.description, DEFAULT_DESCRIPTION)));
|
||||||
|
type.setDescription(desc);
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
121
src/main/java/de/kosit/validationtool/config/SchemaBuilder.java
Normal file
121
src/main/java/de/kosit/validationtool/config/SchemaBuilder.java
Normal file
|
|
@ -0,0 +1,121 @@
|
||||||
|
package de.kosit.validationtool.config;
|
||||||
|
|
||||||
|
import static org.apache.commons.lang3.ObjectUtils.isNotEmpty;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
import javax.xml.validation.Schema;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.tuple.ImmutablePair;
|
||||||
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import de.kosit.validationtool.impl.ContentRepository;
|
||||||
|
import de.kosit.validationtool.impl.model.Result;
|
||||||
|
import de.kosit.validationtool.model.scenarios.ResourceType;
|
||||||
|
import de.kosit.validationtool.model.scenarios.ValidateWithXmlSchema;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builder for Schema validation configuration.
|
||||||
|
*
|
||||||
|
* @author Andreas Penski
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class SchemaBuilder implements Builder<Pair<ValidateWithXmlSchema, Schema>> {
|
||||||
|
|
||||||
|
private static final String DEFAULT_NAME = "manually configured";
|
||||||
|
|
||||||
|
private Schema schema;
|
||||||
|
|
||||||
|
private URI schemaLocation;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Result<Pair<ValidateWithXmlSchema, Schema>, String> build(final ContentRepository repository) {
|
||||||
|
if (this.schema == null && this.schemaLocation == null) {
|
||||||
|
return createError("Must supply schema location and/or schema");
|
||||||
|
}
|
||||||
|
Result<Pair<ValidateWithXmlSchema, Schema>, String> result;
|
||||||
|
try {
|
||||||
|
if (this.schema == null) {
|
||||||
|
this.schema = repository.createSchema(this.schemaLocation);
|
||||||
|
}
|
||||||
|
result = new Result<>(new ImmutablePair<>(createObject(), this.schema));
|
||||||
|
} catch (final IllegalStateException e) {
|
||||||
|
log.error(e.getMessage(), e);
|
||||||
|
result = createError(String.format("Can not create schema based %s. Exception is %s", this.schemaLocation, e.getMessage()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ValidateWithXmlSchema createObject() {
|
||||||
|
final ValidateWithXmlSchema o = new ValidateWithXmlSchema();
|
||||||
|
final ResourceType r = new ResourceType();
|
||||||
|
r.setName(isNotEmpty(this.name) ? this.name : DEFAULT_NAME);
|
||||||
|
r.setLocation(this.schemaLocation.toASCIIString());
|
||||||
|
o.getResource().add(r);
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Result<Pair<ValidateWithXmlSchema, Schema>, String> createError(final String msg) {
|
||||||
|
return new Result<>(null, Collections.singletonList(msg));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a specific precompiled schema to check.
|
||||||
|
*
|
||||||
|
* @param schema the {@link Schema}
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public SchemaBuilder schema(final Schema schema) {
|
||||||
|
this.schema = schema;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a specific schema location either to compile or to document the precompiled one .
|
||||||
|
*
|
||||||
|
* @param schemaLocation the schema location as uri
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public SchemaBuilder schemaLocation(final URI schemaLocation) {
|
||||||
|
this.schemaLocation = schemaLocation;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a specific schema location either to compile or to document the precompiled one .
|
||||||
|
*
|
||||||
|
* @param schemaLocation the schema location as uri
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public SchemaBuilder schemaLocation(final String schemaLocation) {
|
||||||
|
return schemaLocation(URI.create(schemaLocation));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a specific schema location either to compile or to document the precompiled one .
|
||||||
|
*
|
||||||
|
* @param schemaLocation the schema location as uri
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public SchemaBuilder schemaLocation(final Path schemaLocation) {
|
||||||
|
return schemaLocation(schemaLocation.toUri());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a specific name to identify this schema.
|
||||||
|
*
|
||||||
|
* @param name the name of the schema
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public SchemaBuilder name(final String name) {
|
||||||
|
this.name = name;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,116 @@
|
||||||
|
package de.kosit.validationtool.config;
|
||||||
|
|
||||||
|
import static org.apache.commons.lang3.ObjectUtils.isNotEmpty;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.tuple.ImmutablePair;
|
||||||
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import de.kosit.validationtool.impl.ContentRepository;
|
||||||
|
import de.kosit.validationtool.impl.Scenario.Transformation;
|
||||||
|
import de.kosit.validationtool.impl.model.Result;
|
||||||
|
import de.kosit.validationtool.model.scenarios.ResourceType;
|
||||||
|
import de.kosit.validationtool.model.scenarios.ValidateWithSchematron;
|
||||||
|
|
||||||
|
import net.sf.saxon.s9api.XsltExecutable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builder for schematron validation configuration.
|
||||||
|
*
|
||||||
|
* @author Andreas Penski
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class SchematronBuilder implements Builder<Pair<ValidateWithSchematron, Transformation>> {
|
||||||
|
|
||||||
|
private static final String DEFAULT_NAME = "manually configured";
|
||||||
|
|
||||||
|
private XsltExecutable executable;
|
||||||
|
|
||||||
|
private URI source;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Result<Pair<ValidateWithSchematron, Transformation>, String> build(final ContentRepository repository) {
|
||||||
|
if (this.executable == null && this.source == null) {
|
||||||
|
return createError("Must supply source location and/or executable");
|
||||||
|
}
|
||||||
|
final ValidateWithSchematron object = createObject();
|
||||||
|
Result<Pair<ValidateWithSchematron, Transformation>, String> result;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (this.executable == null) {
|
||||||
|
this.executable = repository.createSchematronTransformation(object).getExecutable();
|
||||||
|
}
|
||||||
|
result = new Result<>(new ImmutablePair<>(object, new Transformation(this.executable, object.getResource())));
|
||||||
|
} catch (final IllegalStateException e) {
|
||||||
|
log.error(e.getMessage(), e);
|
||||||
|
result = createError(
|
||||||
|
String.format("Can not create schematron configuration based on %s. Exception is %s", this.source, e.getMessage()));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ValidateWithSchematron createObject() {
|
||||||
|
final ValidateWithSchematron o = new ValidateWithSchematron();
|
||||||
|
final ResourceType r = new ResourceType();
|
||||||
|
r.setLocation(this.source.toASCIIString());
|
||||||
|
r.setName(isNotEmpty(this.name) ? this.name : DEFAULT_NAME);
|
||||||
|
o.setResource(r);
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Result<Pair<ValidateWithSchematron, Transformation>, String> createError(final String msg) {
|
||||||
|
return new Result<>(null, Collections.singletonList(msg));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifices a source for this schematron validation. This is either used to compile the schematron transformation or
|
||||||
|
* as documentation for a precompiled tranformation.
|
||||||
|
*
|
||||||
|
* @param source the source
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public SchematronBuilder source(final String source) {
|
||||||
|
return source(URI.create(source));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifices a source for this schematron validation. This is either used to compile the schematron transformation or
|
||||||
|
* as documentation for a precompiled tranformation.
|
||||||
|
*
|
||||||
|
* @param source the source
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public SchematronBuilder source(final URI source) {
|
||||||
|
this.source = source;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifices a source for this schematron validation. This is either used to compile the schematron transformation or
|
||||||
|
* as documentation for a precompiled tranformation.
|
||||||
|
*
|
||||||
|
* @param source the source
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public SchematronBuilder source(final Path source) {
|
||||||
|
return source(source.toUri());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the name of the schematron source to a specific value.
|
||||||
|
*
|
||||||
|
* @param name the name
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public SchematronBuilder name(final String name) {
|
||||||
|
this.name = name;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,83 @@
|
||||||
|
package de.kosit.validationtool.config;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.StreamSupport;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.ArrayUtils;
|
||||||
|
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import de.kosit.validationtool.impl.ContentRepository;
|
||||||
|
import de.kosit.validationtool.impl.model.Result;
|
||||||
|
|
||||||
|
import net.sf.saxon.s9api.XPathExecutable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal class to represent xpath configuration.
|
||||||
|
*
|
||||||
|
* @author Andreas Penski
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
class XPathBuilder implements Builder<XPathExecutable> {
|
||||||
|
|
||||||
|
private static final String[] IGNORED_PREFIXES = new String[] { "xsd" };
|
||||||
|
|
||||||
|
private String xpath;
|
||||||
|
|
||||||
|
private XPathExecutable executable;
|
||||||
|
|
||||||
|
@Setter(AccessLevel.PACKAGE)
|
||||||
|
@Getter(AccessLevel.PACKAGE)
|
||||||
|
private Map<String, String> namespaces;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the xpath expression.
|
||||||
|
*
|
||||||
|
* @return xpath expression
|
||||||
|
*/
|
||||||
|
public String getXPath() {
|
||||||
|
return this.xpath == null && this.executable != null ? this.executable.getUnderlyingExpression().getInternalExpression().toString()
|
||||||
|
: this.xpath;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Result<XPathExecutable, String> build(final ContentRepository repository) {
|
||||||
|
if (this.executable == null && this.xpath == null) {
|
||||||
|
return createError("No configuration for xpath expression found");
|
||||||
|
}
|
||||||
|
if (this.executable == null) {
|
||||||
|
this.executable = repository.createXPath(this.xpath, this.namespaces);
|
||||||
|
} else {
|
||||||
|
this.xpath = extractExpression();
|
||||||
|
this.namespaces = extractNamespaces();
|
||||||
|
}
|
||||||
|
return new Result<>(this.executable);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, String> extractNamespaces() {
|
||||||
|
final Map<String, String> ns = new HashMap<>();
|
||||||
|
final Iterator<String> iterator = this.executable.getUnderlyingExpression().getInternalExpression().getRetainedStaticContext()
|
||||||
|
.iteratePrefixes();
|
||||||
|
final Iterable<String> iterable = () -> iterator;
|
||||||
|
StreamSupport.stream(iterable.spliterator(), false).filter(e -> !ArrayUtils.contains(IGNORED_PREFIXES, e)).forEach(e -> {
|
||||||
|
ns.put(e,
|
||||||
|
this.executable.getUnderlyingExpression().getInternalExpression().getRetainedStaticContext().getURIForPrefix(e, false));
|
||||||
|
});
|
||||||
|
return ns;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String extractExpression() {
|
||||||
|
return this.executable.getUnderlyingExpression().getInternalExpression().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Result<XPathExecutable, String> createError(final String msg) {
|
||||||
|
return new Result<>(null, Collections.singletonList(msg));
|
||||||
|
}
|
||||||
|
}
|
||||||
114
src/main/java/de/kosit/validationtool/daemon/Daemon.java
Normal file
114
src/main/java/de/kosit/validationtool/daemon/Daemon.java
Normal file
|
|
@ -0,0 +1,114 @@
|
||||||
|
package de.kosit.validationtool.daemon;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
|
import javax.xml.transform.Transformer;
|
||||||
|
import javax.xml.transform.TransformerException;
|
||||||
|
import javax.xml.transform.dom.DOMSource;
|
||||||
|
import javax.xml.transform.stream.StreamResult;
|
||||||
|
|
||||||
|
import org.w3c.dom.Document;
|
||||||
|
|
||||||
|
import com.sun.net.httpserver.HttpExchange;
|
||||||
|
import com.sun.net.httpserver.HttpServer;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import de.kosit.validationtool.api.Configuration;
|
||||||
|
import de.kosit.validationtool.impl.DefaultCheck;
|
||||||
|
import de.kosit.validationtool.impl.ObjectFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HTTP-Daemon für die Bereitstellung der Prüf-Funktionalität via http.
|
||||||
|
*
|
||||||
|
* @author Roula Antoun
|
||||||
|
*/
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Setter
|
||||||
|
@Getter
|
||||||
|
@Slf4j
|
||||||
|
public class Daemon {
|
||||||
|
|
||||||
|
private final String hostName;
|
||||||
|
|
||||||
|
private final int port;
|
||||||
|
|
||||||
|
private final int threadCount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Methode, die die Antwort als String-Text schreibt
|
||||||
|
*
|
||||||
|
* @param httpExchange um den Antwort Body zu erhalten
|
||||||
|
* @param rCode der Code-Status
|
||||||
|
* @param response die String antwort, die ich anzeigen möchte
|
||||||
|
*/
|
||||||
|
static void writeError(final HttpExchange httpExchange, final int rCode, final String response) throws IOException {
|
||||||
|
httpExchange.sendResponseHeaders(rCode, response.length());
|
||||||
|
final OutputStream os = httpExchange.getResponseBody();
|
||||||
|
os.write(response.getBytes());
|
||||||
|
os.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Methode, die die Antwort als String-Text schreibt
|
||||||
|
*
|
||||||
|
* @param httpExchange um den Antwort Body zu erhalten
|
||||||
|
* @param doc der Report
|
||||||
|
*/
|
||||||
|
static void writeOutputstreamArray(final HttpExchange httpExchange, final Document doc)
|
||||||
|
throws IOException, TransformerException {
|
||||||
|
final byte[] bytes = serialize(doc);
|
||||||
|
final OutputStream os = httpExchange.getResponseBody();
|
||||||
|
httpExchange.getResponseHeaders().add("Content-Type", "application/xml");
|
||||||
|
httpExchange.sendResponseHeaders(200, bytes.length);
|
||||||
|
os.write(bytes);
|
||||||
|
os.close();
|
||||||
|
log.debug("Xml File erzeugen ist Fertig ");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Methode zum Serialisieren des Dokuments.
|
||||||
|
*
|
||||||
|
* @param report Vom Typ Dokument, aka Report .
|
||||||
|
*/
|
||||||
|
static byte[] serialize(final Document report) throws TransformerException {
|
||||||
|
|
||||||
|
try ( final ByteArrayOutputStream bArrayOS = new ByteArrayOutputStream() ) {
|
||||||
|
final DOMSource source = new DOMSource(report);
|
||||||
|
final StreamResult streamResult = new StreamResult(bArrayOS);
|
||||||
|
final Transformer transformer = ObjectFactory.createTransformer(true);
|
||||||
|
transformer.transform(source, streamResult);
|
||||||
|
return bArrayOS.toByteArray();
|
||||||
|
} catch (final IOException e) {
|
||||||
|
log.error("Report {}", e.getMessage(), e);
|
||||||
|
throw new IllegalStateException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Methode zum Starten des Servers
|
||||||
|
*
|
||||||
|
* @param config the configuration to use
|
||||||
|
*/
|
||||||
|
public void startServer(final Configuration config) {
|
||||||
|
HttpServer server = null;
|
||||||
|
try {
|
||||||
|
server = HttpServer.create(new InetSocketAddress(this.hostName, this.port), 0);
|
||||||
|
final DefaultCheck check = new DefaultCheck(config);
|
||||||
|
server.createContext("/", new HttpServerHandler(check));
|
||||||
|
server.createContext("/health", new HealthHandler(config));
|
||||||
|
server.setExecutor(Executors.newFixedThreadPool(this.threadCount));
|
||||||
|
server.start();
|
||||||
|
log.info("Server unter Port {} ist erfolgreich gestartet", this.port);
|
||||||
|
} catch (final IOException e) {
|
||||||
|
log.error("Fehler beim HttpServer erstellen: {}", e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
141
src/main/java/de/kosit/validationtool/daemon/HealthHandler.java
Normal file
141
src/main/java/de/kosit/validationtool/daemon/HealthHandler.java
Normal file
|
|
@ -0,0 +1,141 @@
|
||||||
|
package de.kosit.validationtool.daemon;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
|
import javax.xml.transform.TransformerException;
|
||||||
|
|
||||||
|
import org.w3c.dom.Document;
|
||||||
|
import org.w3c.dom.Element;
|
||||||
|
import org.w3c.dom.Node;
|
||||||
|
|
||||||
|
import com.sun.net.httpserver.HttpExchange;
|
||||||
|
import com.sun.net.httpserver.HttpHandler;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import de.kosit.validationtool.api.Configuration;
|
||||||
|
import de.kosit.validationtool.impl.ObjectFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wir benötigen einen Handler, der zur Verarbeitung von HTTP-Anforderungen aufgerufen wird , und hier für Verarbeitung
|
||||||
|
* das GET Request um Health-Endpunkt zu erstellen. Die Klasse HealthHandler implementiert diese Schnittstelle
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
class HealthHandler implements HttpHandler {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Klasse zur Erzeugung Health Xml , die optiamle Status.
|
||||||
|
*
|
||||||
|
* @author Roula Antoun
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
static class Health {
|
||||||
|
|
||||||
|
private final long freeMemory;
|
||||||
|
|
||||||
|
private final long maxMemory;
|
||||||
|
|
||||||
|
private final long totalMemory;
|
||||||
|
|
||||||
|
private final Configuration config;
|
||||||
|
|
||||||
|
Health(final Configuration config) {
|
||||||
|
|
||||||
|
final Runtime runtime = Runtime.getRuntime();
|
||||||
|
this.freeMemory = runtime.freeMemory();
|
||||||
|
this.maxMemory = runtime.maxMemory();
|
||||||
|
this.totalMemory = runtime.totalMemory();
|
||||||
|
this.config = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Methode, die schreibt das Health Xml für optimale Status
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
Document writeHealthXml() {
|
||||||
|
final DocumentBuilder dBuilder = ObjectFactory.createDocumentBuilder(false);
|
||||||
|
final Document doc = dBuilder.newDocument();
|
||||||
|
final Element rootElement = doc.createElementNS("https://localhost:8080/Health", "Health");
|
||||||
|
doc.appendChild(rootElement);
|
||||||
|
rootElement.appendChild(getMemory(doc, this.freeMemory, this.maxMemory, this.totalMemory));
|
||||||
|
rootElement.appendChild(getState(doc));
|
||||||
|
rootElement.appendChild(getScenario(doc, this.config));
|
||||||
|
return doc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Methode, die schreibt das System Status Node im Xml File
|
||||||
|
*
|
||||||
|
* @param doc Vom Typ Dokument.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private static Node getState(final Document doc) {
|
||||||
|
final Element state = doc.createElement("state");
|
||||||
|
state.setAttribute("indicator", "OK");
|
||||||
|
final Element stateNode = doc.createElement("message");
|
||||||
|
stateNode.appendChild(doc.createTextNode("System is up and running normally"));
|
||||||
|
state.appendChild(stateNode);
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Methode, die schreibt das Scnarios Information Node im Xml File
|
||||||
|
*
|
||||||
|
* @param doc Vom Typ Dokument .
|
||||||
|
* @param config Vom Typ {@link Configuration} das verwendete scenario.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private static Node getScenario(final Document doc, final Configuration config) {
|
||||||
|
final Element scenario = doc.createElement("scenario");
|
||||||
|
final Element scenarioNameNode = doc.createElement("name");
|
||||||
|
scenarioNameNode.appendChild(doc.createTextNode(config.getName()));
|
||||||
|
scenario.appendChild(scenarioNameNode);
|
||||||
|
return scenario;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Methode, die schreibt das Scnarios Information Node im Xml File
|
||||||
|
*
|
||||||
|
* @param doc Vom Typ Dokument .
|
||||||
|
* @param freeMemory Vom Typ long , der freier Speicher.
|
||||||
|
* @param maxMemory Vom Typ long , der maximaler Speicher
|
||||||
|
* @param totalMemory Vom Typ long , der Gesamte speicher.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private static Node getMemory(final Document doc, final long freeMemory, final long maxMemory, final long totalMemory) {
|
||||||
|
final Element memory = doc.createElement("memoryState");
|
||||||
|
final String freeM = Long.toString(freeMemory);
|
||||||
|
final Element freeMNode = doc.createElement("freeMemory");
|
||||||
|
freeMNode.appendChild(doc.createTextNode(freeM));
|
||||||
|
memory.appendChild(freeMNode);
|
||||||
|
final String maxM = Long.toString(maxMemory);
|
||||||
|
final Element maxMNode = doc.createElement("maxMemory");
|
||||||
|
maxMNode.appendChild(doc.createTextNode(maxM));
|
||||||
|
memory.appendChild(maxMNode);
|
||||||
|
final String totalM = Long.toString(totalMemory);
|
||||||
|
final Element totalMNode = doc.createElement("totalMemory");
|
||||||
|
totalMNode.appendChild(doc.createTextNode(totalM));
|
||||||
|
memory.appendChild(totalMNode);
|
||||||
|
return memory;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Configuration scenarios;
|
||||||
|
|
||||||
|
HealthHandler(final Configuration config) {
|
||||||
|
this.scenarios = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handle(final HttpExchange httpExchange) throws IOException {
|
||||||
|
final Health health = new Health(this.scenarios);
|
||||||
|
final Document doc = health.writeHealthXml();
|
||||||
|
try {
|
||||||
|
Daemon.writeOutputstreamArray(httpExchange, doc);
|
||||||
|
} catch (final TransformerException e) {
|
||||||
|
Daemon.writeError(httpExchange, 500, e.getMessage());
|
||||||
|
log.error("Fehler beim Erzeugen der Status-Information", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,61 @@
|
||||||
|
package de.kosit.validationtool.daemon;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
|
||||||
|
import com.sun.net.httpserver.HttpExchange;
|
||||||
|
import com.sun.net.httpserver.HttpHandler;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import de.kosit.validationtool.api.Check;
|
||||||
|
import de.kosit.validationtool.api.InputFactory;
|
||||||
|
import de.kosit.validationtool.impl.input.SourceInput;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wir benötigen einen Handler, der zur Verarbeitung von HTTP-Anforderungen aufgerufen wird um hier die Verarbeitung des
|
||||||
|
* POST Request zu realisieren.
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
class HttpServerHandler implements HttpHandler {
|
||||||
|
|
||||||
|
private static final AtomicLong counter = new AtomicLong(0);
|
||||||
|
|
||||||
|
private final Check implemenation;
|
||||||
|
|
||||||
|
HttpServerHandler(final Check check) {
|
||||||
|
this.implemenation = check;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Methode, die eine gegebene Anforderung verarbeitet und eine entsprechende Antwort generiert
|
||||||
|
*
|
||||||
|
* @param httpExchange kapselt eine empfangene HTTP-Anforderung und eine Antwort, die in einem Exchange generiert werden
|
||||||
|
* soll.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void handle(final HttpExchange httpExchange) throws IOException {
|
||||||
|
try {
|
||||||
|
log.debug("Incoming request");
|
||||||
|
final String requestMethod = httpExchange.getRequestMethod();
|
||||||
|
if (requestMethod.equals("POST")) {
|
||||||
|
final InputStream inputStream = httpExchange.getRequestBody();
|
||||||
|
|
||||||
|
if (inputStream.available() > 0) {
|
||||||
|
final SourceInput serverInput = (SourceInput) InputFactory.read(inputStream, "Prüfling" + counter.incrementAndGet());
|
||||||
|
Daemon.writeOutputstreamArray(httpExchange, this.implemenation.check(serverInput));
|
||||||
|
} else {
|
||||||
|
Daemon.writeError(httpExchange, 400, "XML-Inhalt erforderlich!");
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Daemon.writeError(httpExchange, 405, "Es ist nur die POST-Methode erlaubt!");
|
||||||
|
}
|
||||||
|
} catch (final Exception e) {
|
||||||
|
Daemon.writeError(httpExchange, 500, "Interner Fehler bei der Verarbeitung des Requests: " + e.getMessage());
|
||||||
|
log.error("Es ist ein Fehler aufgetreten. Das Dokument kann nicht geprüft werden", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -34,6 +34,8 @@ import lombok.RequiredArgsConstructor;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import de.kosit.validationtool.impl.xml.RelativeUriResolver;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link LSResourceResolver} der objekte relativ zu einem Basis-Pfad aus dem Classpath der Anwendung laden kann.
|
* {@link LSResourceResolver} der objekte relativ zu einem Basis-Pfad aus dem Classpath der Anwendung laden kann.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -24,11 +24,13 @@ import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import javax.xml.transform.Source;
|
import javax.xml.transform.Source;
|
||||||
|
import javax.xml.transform.TransformerException;
|
||||||
import javax.xml.transform.URIResolver;
|
import javax.xml.transform.URIResolver;
|
||||||
import javax.xml.transform.stream.StreamSource;
|
import javax.xml.transform.stream.StreamSource;
|
||||||
import javax.xml.validation.Schema;
|
import javax.xml.validation.Schema;
|
||||||
|
|
@ -40,12 +42,16 @@ import org.xml.sax.SAXException;
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import de.kosit.validationtool.api.ResolvingConfigurationStrategy;
|
||||||
import de.kosit.validationtool.impl.Scenario.Transformation;
|
import de.kosit.validationtool.impl.Scenario.Transformation;
|
||||||
|
import de.kosit.validationtool.impl.xml.RelativeUriResolver;
|
||||||
import de.kosit.validationtool.model.scenarios.NamespaceType;
|
import de.kosit.validationtool.model.scenarios.NamespaceType;
|
||||||
import de.kosit.validationtool.model.scenarios.ResourceType;
|
import de.kosit.validationtool.model.scenarios.ResourceType;
|
||||||
import de.kosit.validationtool.model.scenarios.ScenarioType;
|
import de.kosit.validationtool.model.scenarios.ScenarioType;
|
||||||
|
import de.kosit.validationtool.model.scenarios.ValidateWithSchematron;
|
||||||
|
|
||||||
import net.sf.saxon.s9api.Processor;
|
import net.sf.saxon.s9api.Processor;
|
||||||
import net.sf.saxon.s9api.SaxonApiException;
|
import net.sf.saxon.s9api.SaxonApiException;
|
||||||
|
|
@ -70,9 +76,16 @@ public class ContentRepository {
|
||||||
|
|
||||||
private final URI repository;
|
private final URI repository;
|
||||||
|
|
||||||
private final ResolvingMode mode = ResolvingMode.STRICT_RELATIVE;
|
private final URIResolver resolver;
|
||||||
|
|
||||||
private Source resolve(final URL resource) {
|
@Setter
|
||||||
|
private SchemaFactory schemaFactory;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
@Getter
|
||||||
|
private ResolvingConfigurationStrategy resolvingConfigurationStrategy;
|
||||||
|
|
||||||
|
private static Source resolve(final URL resource) {
|
||||||
try {
|
try {
|
||||||
return new StreamSource(resource.openStream(), resource.toURI().getRawPath());
|
return new StreamSource(resource.openStream(), resource.toURI().getRawPath());
|
||||||
} catch (final IOException | URISyntaxException e) {
|
} catch (final IOException | URISyntaxException e) {
|
||||||
|
|
@ -82,7 +95,7 @@ public class ContentRepository {
|
||||||
|
|
||||||
private Schema createSchema(final Source[] schemaSources, final LSResourceResolver resourceResolver) {
|
private Schema createSchema(final Source[] schemaSources, final LSResourceResolver resourceResolver) {
|
||||||
try {
|
try {
|
||||||
final SchemaFactory sf = ObjectFactory.createSchemaFactory();
|
final SchemaFactory sf = this.schemaFactory;
|
||||||
sf.setResourceResolver(resourceResolver);
|
sf.setResourceResolver(resourceResolver);
|
||||||
return sf.newSchema(schemaSources);
|
return sf.newSchema(schemaSources);
|
||||||
} catch (final SAXException e) {
|
} catch (final SAXException e) {
|
||||||
|
|
@ -106,9 +119,13 @@ public class ContentRepository {
|
||||||
final CollectingErrorEventHandler listener = new CollectingErrorEventHandler();
|
final CollectingErrorEventHandler listener = new CollectingErrorEventHandler();
|
||||||
try {
|
try {
|
||||||
xsltCompiler.setErrorListener(listener);
|
xsltCompiler.setErrorListener(listener);
|
||||||
xsltCompiler.setURIResolver(createResolver());
|
final URIResolver resolver = getResolver();
|
||||||
|
if (resolver != null) {
|
||||||
|
// otherwise use default resolver
|
||||||
|
xsltCompiler.setURIResolver(resolver);
|
||||||
|
}
|
||||||
|
|
||||||
return xsltCompiler.compile(resolve(uri));
|
return xsltCompiler.compile(resolveInRepository(uri));
|
||||||
} catch (final SaxonApiException e) {
|
} catch (final SaxonApiException e) {
|
||||||
listener.getErrors().forEach(event -> event.log(log));
|
listener.getErrors().forEach(event -> event.log(log));
|
||||||
throw new IllegalStateException("Can not compile xslt executable for uri " + uri, e);
|
throw new IllegalStateException("Can not compile xslt executable for uri " + uri, e);
|
||||||
|
|
@ -130,6 +147,10 @@ public class ContentRepository {
|
||||||
return createSchema(url, null);
|
return createSchema(url, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Schema createSchema(final URI uri) {
|
||||||
|
return createSchema(new Source[] { resolveInRepository(uri) });
|
||||||
|
}
|
||||||
|
|
||||||
public Schema createSchema(final URL url, final LSResourceResolver resourceResolver) {
|
public Schema createSchema(final URL url, final LSResourceResolver resourceResolver) {
|
||||||
log.info("Load schema from source {}", url.getPath());
|
log.info("Load schema from source {}", url.getPath());
|
||||||
return createSchema(new Source[] { resolve(url) }, resourceResolver);
|
return createSchema(new Source[] { resolve(url) }, resourceResolver);
|
||||||
|
|
@ -150,11 +171,11 @@ public class ContentRepository {
|
||||||
* @return ReportInput-Schema
|
* @return ReportInput-Schema
|
||||||
*/
|
*/
|
||||||
public Schema getReportInputSchema() {
|
public Schema getReportInputSchema() {
|
||||||
if (reportInputSchema == null) {
|
if (this.reportInputSchema == null) {
|
||||||
final Source source = resolve(ContentRepository.class.getResource("/xsd/createReportInput.xsd"));
|
final Source source = resolve(ContentRepository.class.getResource("/xsd/createReportInput.xsd"));
|
||||||
reportInputSchema = createSchema(new Source[] { source }, new ClassPathResourceResolver("/xsd"));
|
this.reportInputSchema = createSchema(new Source[] { source }, new ClassPathResourceResolver("/xsd"));
|
||||||
}
|
}
|
||||||
return reportInputSchema;
|
return this.reportInputSchema;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -164,7 +185,7 @@ public class ContentRepository {
|
||||||
* @return das Schema
|
* @return das Schema
|
||||||
*/
|
*/
|
||||||
public Schema createSchema(final Collection<String> uris) {
|
public Schema createSchema(final Collection<String> uris) {
|
||||||
return createSchema(uris.stream().map(s -> resolve(URI.create(s))).toArray(Source[]::new));
|
return createSchema(uris.stream().map(s -> resolveInRepository(URI.create(s))).toArray(Source[]::new));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -182,10 +203,20 @@ public class ContentRepository {
|
||||||
return schema;
|
return schema;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Source resolve(final URI source) {
|
private Source resolveInRepository(final URI source) {
|
||||||
final URI resolved = this.mode.resolve(source, this.repository);
|
try {
|
||||||
|
if (this.resolver == null) {
|
||||||
|
// TODO wie wird ohne resolver das richtige Artefakt gefunden?
|
||||||
|
// assume local
|
||||||
|
final URI resolved = RelativeUriResolver.resolve(source, this.repository);
|
||||||
return new StreamSource(resolved.toASCIIString());
|
return new StreamSource(resolved.toASCIIString());
|
||||||
}
|
}
|
||||||
|
return this.resolver.resolve(source.toString(), this.repository.toString());
|
||||||
|
} catch (final TransformerException e) {
|
||||||
|
log.error("Error resolving source {}", source, e);
|
||||||
|
throw new IllegalStateException(String.format("Can not resolve %s in repository %s", source, this.repository), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Erzeugt einen [@link XPathExecutable} auf Basis der angegebenen Informationen.
|
* Erzeugt einen [@link XPathExecutable} auf Basis der angegebenen Informationen.
|
||||||
|
|
@ -212,8 +243,8 @@ public class ContentRepository {
|
||||||
*
|
*
|
||||||
* @return ein neuer Resolver
|
* @return ein neuer Resolver
|
||||||
*/
|
*/
|
||||||
public URIResolver createResolver() {
|
public URIResolver getResolver() {
|
||||||
return this.mode.createResolver(this.repository);
|
return this.resolver;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -223,6 +254,10 @@ public class ContentRepository {
|
||||||
*/
|
*/
|
||||||
public Transformation createReportTransformation(final ScenarioType t) {
|
public Transformation createReportTransformation(final ScenarioType t) {
|
||||||
final ResourceType resource = t.getCreateReport().getResource();
|
final ResourceType resource = t.getCreateReport().getResource();
|
||||||
|
return createTransformation(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Transformation createTransformation(final ResourceType resource) {
|
||||||
final XsltExecutable executable = loadXsltScript(URI.create(resource.getLocation()));
|
final XsltExecutable executable = loadXsltScript(URI.create(resource.getLocation()));
|
||||||
return new Transformation(executable, resource);
|
return new Transformation(executable, resource);
|
||||||
}
|
}
|
||||||
|
|
@ -238,4 +273,13 @@ public class ContentRepository {
|
||||||
.collect(Collectors.toMap(NamespaceType::getPrefix, NamespaceType::getValue));
|
.collect(Collectors.toMap(NamespaceType::getPrefix, NamespaceType::getValue));
|
||||||
return createXPath(s.getAcceptMatch(), namespaces);
|
return createXPath(s.getAcceptMatch(), namespaces);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<Transformation> createSchematronTransformations(final ScenarioType s) {
|
||||||
|
return s.getValidateWithSchematron() != null && s.getValidateWithSchematron().isEmpty() ? Collections.emptyList()
|
||||||
|
: s.getValidateWithSchematron().stream().map(this::createSchematronTransformation).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Transformation createSchematronTransformation(final ValidateWithSchematron validateWithSchematron) {
|
||||||
|
return createTransformation(validateWithSchematron.getResource());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,6 @@ import javax.xml.bind.Unmarshaller;
|
||||||
import javax.xml.bind.ValidationEventHandler;
|
import javax.xml.bind.ValidationEventHandler;
|
||||||
import javax.xml.bind.annotation.XmlRegistry;
|
import javax.xml.bind.annotation.XmlRegistry;
|
||||||
import javax.xml.namespace.QName;
|
import javax.xml.namespace.QName;
|
||||||
import javax.xml.parsers.DocumentBuilder;
|
|
||||||
import javax.xml.stream.XMLInputFactory;
|
import javax.xml.stream.XMLInputFactory;
|
||||||
import javax.xml.stream.XMLOutputFactory;
|
import javax.xml.stream.XMLOutputFactory;
|
||||||
import javax.xml.stream.XMLStreamException;
|
import javax.xml.stream.XMLStreamException;
|
||||||
|
|
@ -47,7 +46,6 @@ import javax.xml.transform.stream.StreamSource;
|
||||||
import javax.xml.validation.Schema;
|
import javax.xml.validation.Schema;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.w3c.dom.Document;
|
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
|
@ -86,6 +84,15 @@ public class ConversionService {
|
||||||
// context setup
|
// context setup
|
||||||
private JAXBContext jaxbContext;
|
private JAXBContext jaxbContext;
|
||||||
|
|
||||||
|
public JAXBContext
|
||||||
|
|
||||||
|
getJaxbContext() {
|
||||||
|
if (this.jaxbContext == null) {
|
||||||
|
initialize();
|
||||||
|
}
|
||||||
|
return this.jaxbContext;
|
||||||
|
}
|
||||||
|
|
||||||
private static <T> QName createQName(final T model) {
|
private static <T> QName createQName(final T model) {
|
||||||
return new QName(model.getClass().getSimpleName().toLowerCase());
|
return new QName(model.getClass().getSimpleName().toLowerCase());
|
||||||
}
|
}
|
||||||
|
|
@ -141,13 +148,6 @@ public class ConversionService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private JAXBContext getJaxbContext() {
|
|
||||||
if (this.jaxbContext == null) {
|
|
||||||
initialize();
|
|
||||||
}
|
|
||||||
return this.jaxbContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unmarshalls a specifc xml model into a defined java object.
|
* Unmarshalls a specifc xml model into a defined java object.
|
||||||
*
|
*
|
||||||
|
|
@ -233,24 +233,8 @@ public class ConversionService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T> Document writeDocument(final T input) {
|
|
||||||
if (input == null) {
|
|
||||||
throw new ConversionExeption("Can not serialize null");
|
|
||||||
}
|
|
||||||
final DocumentBuilder builder = ObjectFactory.createDocumentBuilder(false);
|
|
||||||
final Document document = builder.newDocument();
|
|
||||||
|
|
||||||
// Marshal the Object to a Document
|
|
||||||
Marshaller marshaller = null;
|
|
||||||
try {
|
|
||||||
marshaller = getJaxbContext().createMarshaller();
|
|
||||||
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
|
|
||||||
marshaller.marshal(input, document);
|
|
||||||
return document;
|
|
||||||
} catch (final JAXBException e) {
|
|
||||||
throw new ConversionExeption(String.format("Error serializing Object %s to document", input.getClass().getName()), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public <T> T readDocument(final Source source, final Class<T> type) {
|
public <T> T readDocument(final Source source, final Class<T> type) {
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
|
|
@ -21,9 +21,15 @@ package de.kosit.validationtool.impl;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.GregorianCalendar;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import javax.xml.datatype.DatatypeConfigurationException;
|
||||||
|
import javax.xml.datatype.DatatypeFactory;
|
||||||
|
import javax.xml.datatype.XMLGregorianCalendar;
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
|
@ -35,6 +41,7 @@ import de.kosit.validationtool.api.XmlError;
|
||||||
import de.kosit.validationtool.impl.tasks.CheckAction;
|
import de.kosit.validationtool.impl.tasks.CheckAction;
|
||||||
import de.kosit.validationtool.impl.tasks.CheckAction.Bag;
|
import de.kosit.validationtool.impl.tasks.CheckAction.Bag;
|
||||||
import de.kosit.validationtool.impl.tasks.ComputeAcceptanceAction;
|
import de.kosit.validationtool.impl.tasks.ComputeAcceptanceAction;
|
||||||
|
import de.kosit.validationtool.impl.tasks.CreateDocumentIdentificationAction;
|
||||||
import de.kosit.validationtool.impl.tasks.CreateReportAction;
|
import de.kosit.validationtool.impl.tasks.CreateReportAction;
|
||||||
import de.kosit.validationtool.impl.tasks.DocumentParseAction;
|
import de.kosit.validationtool.impl.tasks.DocumentParseAction;
|
||||||
import de.kosit.validationtool.impl.tasks.ScenarioSelectionAction;
|
import de.kosit.validationtool.impl.tasks.ScenarioSelectionAction;
|
||||||
|
|
@ -56,15 +63,11 @@ import net.sf.saxon.s9api.Processor;
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class DefaultCheck implements Check {
|
public class DefaultCheck implements Check {
|
||||||
|
|
||||||
@Getter
|
|
||||||
private final ScenarioRepository repository;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
private final ContentRepository contentRepository;
|
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private final ConversionService conversionService;
|
private final ConversionService conversionService;
|
||||||
|
|
||||||
|
private final Configuration configuration;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private final List<CheckAction> checkSteps;
|
private final List<CheckAction> checkSteps;
|
||||||
|
|
||||||
|
|
@ -74,21 +77,19 @@ public class DefaultCheck implements Check {
|
||||||
* @param configuration die Konfiguration
|
* @param configuration die Konfiguration
|
||||||
*/
|
*/
|
||||||
public DefaultCheck(final Configuration configuration) {
|
public DefaultCheck(final Configuration configuration) {
|
||||||
final Processor processor = ObjectFactory.createProcessor();
|
this.configuration = configuration;
|
||||||
|
final ContentRepository content = configuration.getContentRepository();
|
||||||
|
final Processor processor = content.getProcessor();
|
||||||
this.conversionService = new ConversionService();
|
this.conversionService = new ConversionService();
|
||||||
this.repository = new ScenarioRepository(configuration);
|
|
||||||
|
|
||||||
// TODO get rid of it
|
|
||||||
this.contentRepository = configuration.getContentRepository();
|
|
||||||
this.checkSteps = new ArrayList<>();
|
this.checkSteps = new ArrayList<>();
|
||||||
this.checkSteps.add(new DocumentParseAction());
|
this.checkSteps.add(new DocumentParseAction(processor));
|
||||||
this.checkSteps.add(new CreateDocumentIdentificationAction());
|
this.checkSteps.add(new CreateDocumentIdentificationAction());
|
||||||
this.checkSteps.add(new ScenarioSelectionAction(this.repository));
|
this.checkSteps.add(new ScenarioSelectionAction(new ScenarioRepository(configuration)));
|
||||||
this.checkSteps.add(new SchemaValidationAction());
|
this.checkSteps.add(new SchemaValidationAction(content.getResolvingConfigurationStrategy(), processor));
|
||||||
this.checkSteps.add(new SchematronValidationAction(this.contentRepository, this.conversionService));
|
this.checkSteps.add(new SchematronValidationAction(content.getResolver(), this.conversionService));
|
||||||
this.checkSteps
|
this.checkSteps.add(new ValidateReportInputAction(this.conversionService, content.getReportInputSchema()));
|
||||||
.add(new ValidateReportInputAction(this.conversionService, configuration.getContentRepository().getReportInputSchema()));
|
this.checkSteps.add(new CreateReportAction(processor, this.conversionService, content.getResolver()));
|
||||||
this.checkSteps.add(new CreateReportAction(processor, this.conversionService, this.contentRepository));
|
|
||||||
this.checkSteps.add(new ComputeAcceptanceAction());
|
this.checkSteps.add(new ComputeAcceptanceAction());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -97,11 +98,22 @@ public class DefaultCheck implements Check {
|
||||||
final EngineType e = new EngineType();
|
final EngineType e = new EngineType();
|
||||||
e.setName(EngineInformation.getName());
|
e.setName(EngineInformation.getName());
|
||||||
type.setEngine(e);
|
type.setEngine(e);
|
||||||
type.setTimestamp(ObjectFactory.createTimestamp());
|
type.setTimestamp(createTimestamp());
|
||||||
type.setFrameworkVersion(EngineInformation.getFrameworkVersion());
|
type.setFrameworkVersion(EngineInformation.getFrameworkVersion());
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static XMLGregorianCalendar createTimestamp() {
|
||||||
|
try {
|
||||||
|
final GregorianCalendar cal = new GregorianCalendar();
|
||||||
|
cal.setTime(new Date());
|
||||||
|
return DatatypeFactory.newInstance().newXMLGregorianCalendar(cal);
|
||||||
|
|
||||||
|
} catch (final DatatypeConfigurationException e) {
|
||||||
|
throw new IllegalStateException("Can not create timestamp", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Result checkInput(final Input input) {
|
public Result checkInput(final Input input) {
|
||||||
final CheckAction.Bag t = new CheckAction.Bag(input, createReport());
|
final CheckAction.Bag t = new CheckAction.Bag(input, createReport());
|
||||||
|
|
@ -124,7 +136,8 @@ public class DefaultCheck implements Check {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Result createResult(final Bag t) {
|
private Result createResult(final Bag t) {
|
||||||
final DefaultResult result = new DefaultResult(t.getReport(), t.getAcceptStatus(), new HtmlExtractor(this.contentRepository));
|
final DefaultResult result = new DefaultResult(t.getReport(), t.getAcceptStatus(),
|
||||||
|
new HtmlExtractor(this.configuration.getContentRepository().getProcessor()));
|
||||||
result.setWellformed(t.getParserResult().isValid());
|
result.setWellformed(t.getParserResult().isValid());
|
||||||
result.setReportInput(t.getReportInput());
|
result.setReportInput(t.getReportInput());
|
||||||
if (t.getSchemaValidationResult() != null) {
|
if (t.getSchemaValidationResult() != null) {
|
||||||
|
|
|
||||||
|
|
@ -6,13 +6,16 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
import net.sf.saxon.dom.NodeOverNodeInfo;
|
import net.sf.saxon.dom.NodeOverNodeInfo;
|
||||||
|
import net.sf.saxon.s9api.Processor;
|
||||||
import net.sf.saxon.s9api.SaxonApiException;
|
import net.sf.saxon.s9api.SaxonApiException;
|
||||||
import net.sf.saxon.s9api.Serializer;
|
import net.sf.saxon.s9api.Serializer;
|
||||||
|
import net.sf.saxon.s9api.XPathCompiler;
|
||||||
import net.sf.saxon.s9api.XPathExecutable;
|
import net.sf.saxon.s9api.XPathExecutable;
|
||||||
import net.sf.saxon.s9api.XPathSelector;
|
import net.sf.saxon.s9api.XPathSelector;
|
||||||
import net.sf.saxon.s9api.XdmItem;
|
import net.sf.saxon.s9api.XdmItem;
|
||||||
|
|
@ -26,38 +29,51 @@ import net.sf.saxon.s9api.XdmNode;
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class HtmlExtractor {
|
public class HtmlExtractor {
|
||||||
|
|
||||||
private final ContentRepository repository;
|
private final Processor processor;
|
||||||
|
|
||||||
private XPathExecutable executable;
|
private XPathExecutable executable;
|
||||||
|
|
||||||
public List<XdmNode> extract(XdmNode xdmSource) {
|
public List<XdmNode> extract(final XdmNode xdmSource) {
|
||||||
try {
|
try {
|
||||||
final XPathSelector selector = getSelector();
|
final XPathSelector selector = getSelector();
|
||||||
selector.setContextItem(xdmSource);
|
selector.setContextItem(xdmSource);
|
||||||
return selector.stream().map(this::castToNode).collect(Collectors.toList());
|
return selector.stream().map(HtmlExtractor::castToNode).collect(Collectors.toList());
|
||||||
|
|
||||||
} catch (SaxonApiException e) {
|
} catch (final SaxonApiException e) {
|
||||||
throw new IllegalStateException("Can not extract html content", e);
|
throw new IllegalStateException("Can not extract html content", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private XdmNode castToNode(final XdmItem xdmItem) {
|
private static XdmNode castToNode(final XdmItem xdmItem) {
|
||||||
return (XdmNode) xdmItem;
|
return (XdmNode) xdmItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
private XPathSelector getSelector() {
|
private XPathSelector getSelector() {
|
||||||
if (executable == null) {
|
if (this.executable == null) {
|
||||||
Map<String, String> ns = new HashMap<>();
|
final Map<String, String> ns = new HashMap<>();
|
||||||
ns.put("html", "http://www.w3.org/1999/xhtml");
|
ns.put("html", "http://www.w3.org/1999/xhtml");
|
||||||
executable = repository.createXPath("//html:html", ns);
|
this.executable = createXPath("//html:html", ns);
|
||||||
}
|
}
|
||||||
return executable.load();
|
return this.executable.load();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String convertToString(final XdmNode element) {
|
private XPathExecutable createXPath(final String expression, final Map<String, String> namespaces) {
|
||||||
|
try {
|
||||||
|
final XPathCompiler compiler = this.processor.newXPathCompiler();
|
||||||
|
if (namespaces != null) {
|
||||||
|
namespaces.forEach(compiler::declareNamespace);
|
||||||
|
}
|
||||||
|
return compiler.compile(expression);
|
||||||
|
} catch (final SaxonApiException e) {
|
||||||
|
throw new IllegalStateException(String.format("Can not compile xpath match expression '%s'",
|
||||||
|
StringUtils.isNotBlank(expression) ? expression : "EMPTY EXPRESSION"), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String convertToString(final XdmNode element) {
|
||||||
try {
|
try {
|
||||||
final StringWriter writer = new StringWriter();
|
final StringWriter writer = new StringWriter();
|
||||||
final Serializer serializer = ObjectFactory.createProcessor().newSerializer(writer);
|
final Serializer serializer = this.processor.newSerializer(writer);
|
||||||
serializer.serializeNode(element);
|
serializer.serializeNode(element);
|
||||||
return writer.toString();
|
return writer.toString();
|
||||||
} catch (final SaxonApiException e) {
|
} catch (final SaxonApiException e) {
|
||||||
|
|
@ -72,7 +88,7 @@ public class HtmlExtractor {
|
||||||
* @return HTML-Fragment als String
|
* @return HTML-Fragment als String
|
||||||
*/
|
*/
|
||||||
public List<String> extractAsString(final XdmNode node) {
|
public List<String> extractAsString(final XdmNode node) {
|
||||||
return extract(node).stream().map(HtmlExtractor::convertToString).collect(Collectors.toList());
|
return extract(node).stream().map(this::convertToString).collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Element> extractAsElement(final XdmNode node) {
|
public List<Element> extractAsElement(final XdmNode node) {
|
||||||
|
|
|
||||||
|
|
@ -24,13 +24,8 @@ import java.io.UnsupportedEncodingException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Date;
|
|
||||||
import java.util.GregorianCalendar;
|
|
||||||
|
|
||||||
import javax.xml.XMLConstants;
|
import javax.xml.XMLConstants;
|
||||||
import javax.xml.datatype.DatatypeConfigurationException;
|
|
||||||
import javax.xml.datatype.DatatypeFactory;
|
|
||||||
import javax.xml.datatype.XMLGregorianCalendar;
|
|
||||||
import javax.xml.parsers.DocumentBuilder;
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
import javax.xml.parsers.DocumentBuilderFactory;
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
import javax.xml.parsers.ParserConfigurationException;
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
|
|
@ -40,13 +35,6 @@ import javax.xml.transform.Transformer;
|
||||||
import javax.xml.transform.TransformerConfigurationException;
|
import javax.xml.transform.TransformerConfigurationException;
|
||||||
import javax.xml.transform.TransformerException;
|
import javax.xml.transform.TransformerException;
|
||||||
import javax.xml.transform.TransformerFactory;
|
import javax.xml.transform.TransformerFactory;
|
||||||
import javax.xml.validation.Schema;
|
|
||||||
import javax.xml.validation.SchemaFactory;
|
|
||||||
import javax.xml.validation.Validator;
|
|
||||||
|
|
||||||
import org.xml.sax.SAXException;
|
|
||||||
import org.xml.sax.SAXNotRecognizedException;
|
|
||||||
import org.xml.sax.SAXNotSupportedException;
|
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
|
@ -70,6 +58,7 @@ import net.sf.saxon.trans.XPathException;
|
||||||
* @author Andreas Penski
|
* @author Andreas Penski
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
|
@Deprecated
|
||||||
public class ObjectFactory {
|
public class ObjectFactory {
|
||||||
|
|
||||||
private static class SecureUriResolver implements CollectionFinder, OutputURIResolver, UnparsedTextURIResolver {
|
private static class SecureUriResolver implements CollectionFinder, OutputURIResolver, UnparsedTextURIResolver {
|
||||||
|
|
@ -116,7 +105,7 @@ public class ObjectFactory {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ObjectFactory() {
|
ObjectFactory() {
|
||||||
// hide, it's a factory
|
// hide, it's a factory
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -154,13 +143,17 @@ public class ObjectFactory {
|
||||||
public static Transformer createTransformer(final boolean prettyPrint) {
|
public static Transformer createTransformer(final boolean prettyPrint) {
|
||||||
Transformer transformer = null;
|
Transformer transformer = null;
|
||||||
try {
|
try {
|
||||||
transformer = TransformerFactory.newInstance().newTransformer();
|
final TransformerFactory transformerFactory = TransformerFactory.newInstance();
|
||||||
|
transformerFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
|
||||||
|
transformerFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, ""); // Compliant
|
||||||
|
transformer = transformerFactory.newTransformer();
|
||||||
if (prettyPrint) {
|
if (prettyPrint) {
|
||||||
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
|
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
|
||||||
transformer.setOutputProperty(OutputKeys.METHOD, "xml");
|
transformer.setOutputProperty(OutputKeys.METHOD, "xml");
|
||||||
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
|
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
|
||||||
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
|
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
|
||||||
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
|
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
|
||||||
|
|
||||||
}
|
}
|
||||||
return transformer;
|
return transformer;
|
||||||
} catch (final TransformerConfigurationException e) {
|
} catch (final TransformerConfigurationException e) {
|
||||||
|
|
@ -168,21 +161,6 @@ public class ObjectFactory {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Erzeugt einen Zeitstempel zur Verwendung in XML-Objekten
|
|
||||||
*
|
|
||||||
* @return eine Instanz {@link XMLGregorianCalendar}
|
|
||||||
*/
|
|
||||||
public static XMLGregorianCalendar createTimestamp() {
|
|
||||||
try {
|
|
||||||
final GregorianCalendar cal = new GregorianCalendar();
|
|
||||||
cal.setTime(new Date());
|
|
||||||
return DatatypeFactory.newInstance().newXMLGregorianCalendar(cal);
|
|
||||||
|
|
||||||
} catch (final DatatypeConfigurationException e) {
|
|
||||||
throw new IllegalStateException("Can not create timestamp", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static DocumentBuilder createDocumentBuilder(final boolean validating) {
|
public static DocumentBuilder createDocumentBuilder(final boolean validating) {
|
||||||
try {
|
try {
|
||||||
|
|
@ -223,38 +201,6 @@ public class ObjectFactory {
|
||||||
return processor;
|
return processor;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Erzeugt einen Validier für das angegebenen Schema.
|
|
||||||
*
|
|
||||||
* @param schema das Schema mit dem validiert werden soll
|
|
||||||
* @return einen vorkonfigurierten Validator
|
|
||||||
*/
|
|
||||||
public static Validator createValidator(final Schema schema) {
|
|
||||||
final Validator validator = schema.newValidator();
|
|
||||||
try {
|
|
||||||
validator.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");
|
|
||||||
} catch (final SAXNotRecognizedException | SAXNotSupportedException e) {
|
|
||||||
log.warn("Can not disable external DTD access. Maybe an unsupported JAXP implementation is used.");
|
|
||||||
log.debug(e.getMessage(), e);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
validator.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
|
|
||||||
} catch (final SAXNotRecognizedException | SAXNotSupportedException e) {
|
|
||||||
log.warn("Can not disable external DTD access. Maybe an unsupported JAXP implementation is used.");
|
|
||||||
log.debug(e.getMessage(), e);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
return validator;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static SchemaFactory createSchemaFactory() {
|
|
||||||
final SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
|
|
||||||
try {
|
|
||||||
sf.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");
|
|
||||||
sf.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "file");
|
|
||||||
} catch (final SAXException e) {
|
|
||||||
log.warn("Can not disable external DTD access, maybe an unsupported JAXP implementation is used", e);
|
|
||||||
}
|
|
||||||
return sf;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,45 +1,34 @@
|
||||||
package de.kosit.validationtool.impl;
|
package de.kosit.validationtool.impl;
|
||||||
|
|
||||||
import java.net.URI;
|
import lombok.Getter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
import javax.xml.transform.URIResolver;
|
import de.kosit.validationtool.api.ResolvingConfigurationStrategy;
|
||||||
|
import de.kosit.validationtool.impl.xml.StrictLocalResolvingStrategy;
|
||||||
import org.apache.commons.lang3.NotImplementedException;
|
import de.kosit.validationtool.impl.xml.StrictRelativeResolvingStrategy;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines how artefacts are resolved internally.
|
* Defines how artefacts are resolved internally.
|
||||||
*
|
*
|
||||||
* @author Andreas Penski
|
* @author Andreas Penski
|
||||||
*/
|
*/
|
||||||
|
@RequiredArgsConstructor
|
||||||
public enum ResolvingMode {
|
public enum ResolvingMode {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolving using only the configured content repository. No furthing resolving allowed. This
|
* Resolving using only the configured content repository. No furthing resolving allowed. This
|
||||||
*/
|
*/
|
||||||
STRICT_RELATIVE {
|
STRICT_RELATIVE(new StrictRelativeResolvingStrategy()) {
|
||||||
|
|
||||||
@Override
|
|
||||||
public URI resolve(final URI source, final URI repository) {
|
|
||||||
return RelativeUriResolver.resolve(source, repository);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public URIResolver createResolver(final URI repository) {
|
|
||||||
return new RelativeUriResolver(repository);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
STRICT_LOCAL,
|
STRICT_LOCAL(new StrictLocalResolvingStrategy()),
|
||||||
|
|
||||||
JDK_SUPPORTED,
|
JDK_SUPPORTED(null),
|
||||||
|
|
||||||
CUSTOM;
|
CUSTOM(null);
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private final ResolvingConfigurationStrategy strategy;
|
||||||
|
|
||||||
public URI resolve(final URI source, final URI repository) {
|
|
||||||
throw new NotImplementedException("Not yet implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
public URIResolver createResolver(final URI repository) {
|
|
||||||
throw new NotImplementedException("Not yet implemented");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,6 @@ import net.sf.saxon.s9api.XsltExecutable;
|
||||||
* @author Andreas Penski
|
* @author Andreas Penski
|
||||||
*/
|
*/
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
|
|
||||||
@Setter
|
@Setter
|
||||||
@Getter
|
@Getter
|
||||||
public class Scenario {
|
public class Scenario {
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,6 @@ public class ScenarioRepository {
|
||||||
|
|
||||||
public ScenarioRepository(final Configuration configuration) {
|
public ScenarioRepository(final Configuration configuration) {
|
||||||
this.configuration = configuration;
|
this.configuration = configuration;
|
||||||
configuration.build();
|
|
||||||
log.info("Loaded scenarios for {} by {} from {}. The following scenarios are available:\n\n{}", configuration.getName(),
|
log.info("Loaded scenarios for {} by {} from {}. The following scenarios are available:\n\n{}", configuration.getName(),
|
||||||
configuration.getAuthor(), configuration.getDate(), summarizeScenarios());
|
configuration.getAuthor(), configuration.getDate(), summarizeScenarios());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
package de.kosit.validationtool.impl;
|
package de.kosit.validationtool.impl.tasks;
|
||||||
|
|
||||||
import de.kosit.validationtool.impl.tasks.CheckAction;
|
|
||||||
import de.kosit.validationtool.model.reportInput.DocumentIdentificationType;
|
import de.kosit.validationtool.model.reportInput.DocumentIdentificationType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -8,7 +7,7 @@ import de.kosit.validationtool.model.reportInput.DocumentIdentificationType;
|
||||||
*
|
*
|
||||||
* @author Andreas Penski
|
* @author Andreas Penski
|
||||||
*/
|
*/
|
||||||
class CreateDocumentIdentificationAction implements CheckAction {
|
public class CreateDocumentIdentificationAction implements CheckAction {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void check(final Bag transporter) {
|
public void check(final Bag transporter) {
|
||||||
|
|
@ -19,23 +19,31 @@
|
||||||
|
|
||||||
package de.kosit.validationtool.impl.tasks;
|
package de.kosit.validationtool.impl.tasks;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import javax.xml.bind.JAXBException;
|
||||||
|
import javax.xml.bind.Marshaller;
|
||||||
|
import javax.xml.bind.util.JAXBSource;
|
||||||
import javax.xml.transform.URIResolver;
|
import javax.xml.transform.URIResolver;
|
||||||
import javax.xml.transform.dom.DOMSource;
|
|
||||||
|
|
||||||
import org.w3c.dom.Document;
|
import org.xml.sax.ContentHandler;
|
||||||
|
import org.xml.sax.DTDHandler;
|
||||||
|
import org.xml.sax.EntityResolver;
|
||||||
|
import org.xml.sax.ErrorHandler;
|
||||||
|
import org.xml.sax.InputSource;
|
||||||
import org.xml.sax.SAXException;
|
import org.xml.sax.SAXException;
|
||||||
|
import org.xml.sax.SAXNotRecognizedException;
|
||||||
|
import org.xml.sax.SAXNotSupportedException;
|
||||||
|
import org.xml.sax.XMLReader;
|
||||||
import org.xml.sax.helpers.AttributesImpl;
|
import org.xml.sax.helpers.AttributesImpl;
|
||||||
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
import de.kosit.validationtool.impl.CollectingErrorEventHandler;
|
import de.kosit.validationtool.impl.CollectingErrorEventHandler;
|
||||||
import de.kosit.validationtool.impl.ContentRepository;
|
|
||||||
import de.kosit.validationtool.impl.ConversionService;
|
import de.kosit.validationtool.impl.ConversionService;
|
||||||
import de.kosit.validationtool.impl.EngineInformation;
|
import de.kosit.validationtool.impl.EngineInformation;
|
||||||
import de.kosit.validationtool.impl.ObjectFactory;
|
|
||||||
import de.kosit.validationtool.impl.Scenario;
|
import de.kosit.validationtool.impl.Scenario;
|
||||||
import de.kosit.validationtool.model.reportInput.XMLSyntaxError;
|
import de.kosit.validationtool.model.reportInput.XMLSyntaxError;
|
||||||
|
|
||||||
|
|
@ -58,12 +66,108 @@ import net.sf.saxon.s9api.XsltTransformer;
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class CreateReportAction implements CheckAction {
|
public class CreateReportAction implements CheckAction {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper to fix some inconsistencies between sax and saxon. Saxon tries to set some properties which has no effect on
|
||||||
|
* {@link JAXBSource}'s XMLReader, but it throws exceptions on unknown properties. This just drops this exceptions.
|
||||||
|
*/
|
||||||
|
private static class ReaderWrapper implements XMLReader {
|
||||||
|
|
||||||
|
private final XMLReader delegate;
|
||||||
|
|
||||||
|
public ReaderWrapper(final XMLReader xmlReader) {
|
||||||
|
this.delegate = xmlReader;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean getFeature(final String name) throws SAXNotRecognizedException, SAXNotSupportedException {
|
||||||
|
if (name.equals("http://xml.org/sax/features/namespaces")) {
|
||||||
|
return true;
|
||||||
|
} else if (name.equals("http://xml.org/sax/features/namespace-prefixes")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// just return false on unknown properties
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setFeature(final String name, final boolean value) throws SAXNotRecognizedException, SAXNotSupportedException {
|
||||||
|
// this inverts the logic from JaxbSource pseude parser
|
||||||
|
if (name.equals("http://xml.org/sax/features/namespaces") && !value) {
|
||||||
|
throw new SAXNotRecognizedException(name);
|
||||||
|
}
|
||||||
|
if (name.equals("http://xml.org/sax/features/namespace-prefixes") && value) {
|
||||||
|
throw new SAXNotRecognizedException(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getProperty(final String name) throws SAXNotRecognizedException, SAXNotSupportedException {
|
||||||
|
return this.delegate.getProperty(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setProperty(final String name, final Object value) throws SAXNotRecognizedException, SAXNotSupportedException {
|
||||||
|
this.delegate.setProperty(name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setEntityResolver(final EntityResolver resolver) {
|
||||||
|
this.delegate.setEntityResolver(resolver);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EntityResolver getEntityResolver() {
|
||||||
|
return this.delegate.getEntityResolver();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDTDHandler(final DTDHandler handler) {
|
||||||
|
this.delegate.setDTDHandler(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DTDHandler getDTDHandler() {
|
||||||
|
return this.delegate.getDTDHandler();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setContentHandler(final ContentHandler handler) {
|
||||||
|
this.delegate.setContentHandler(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ContentHandler getContentHandler() {
|
||||||
|
return this.delegate.getContentHandler();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setErrorHandler(final ErrorHandler handler) {
|
||||||
|
this.delegate.setErrorHandler(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ErrorHandler getErrorHandler() {
|
||||||
|
return this.delegate.getErrorHandler();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void parse(final InputSource input) throws IOException, SAXException {
|
||||||
|
this.delegate.parse(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void parse(final String systemId) throws IOException, SAXException {
|
||||||
|
this.delegate.parse(systemId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static final String ERROR_MESSAGE_ELEMENT = "error-message";
|
private static final String ERROR_MESSAGE_ELEMENT = "error-message";
|
||||||
|
|
||||||
private final Processor processor;
|
private final Processor processor;
|
||||||
|
|
||||||
private final ConversionService conversionService;
|
private final ConversionService conversionService;
|
||||||
|
|
||||||
private final ContentRepository contentRepository;
|
private final URIResolver resolver;
|
||||||
|
|
||||||
private static XsltExecutable loadFromScenario(final Scenario object) {
|
private static XsltExecutable loadFromScenario(final Scenario object) {
|
||||||
return object.getReportTransformation().getExecutable();
|
return object.getReportTransformation().getExecutable();
|
||||||
|
|
@ -77,14 +181,17 @@ public class CreateReportAction implements CheckAction {
|
||||||
final XdmNode parsedDocument = results.getParserResult().isValid() ? results.getParserResult().getObject()
|
final XdmNode parsedDocument = results.getParserResult().isValid() ? results.getParserResult().getObject()
|
||||||
: createErrorInformation(results.getParserResult().getErrors());
|
: createErrorInformation(results.getParserResult().getErrors());
|
||||||
|
|
||||||
final Document reportInput = this.conversionService.writeDocument(results.getReportInput());
|
final Marshaller marshaller = this.conversionService.getJaxbContext().createMarshaller();
|
||||||
final XdmNode root = documentBuilder.build(new DOMSource(reportInput));
|
final JAXBSource source = new JAXBSource(marshaller, results.getReportInput());
|
||||||
|
// wrap to circumvent inconsistency between sax and saxon
|
||||||
|
source.setXMLReader(new ReaderWrapper(source.getXMLReader()));
|
||||||
|
|
||||||
|
final XdmNode root = documentBuilder.build(source);
|
||||||
final XsltTransformer transformer = getTransformation(results).load();
|
final XsltTransformer transformer = getTransformation(results).load();
|
||||||
transformer.setInitialContextNode(root);
|
transformer.setInitialContextNode(root);
|
||||||
final CollectingErrorEventHandler e = new CollectingErrorEventHandler();
|
final CollectingErrorEventHandler e = new CollectingErrorEventHandler();
|
||||||
final URIResolver resolver = this.contentRepository.createResolver();
|
|
||||||
transformer.setMessageListener(e);
|
transformer.setMessageListener(e);
|
||||||
transformer.setURIResolver(resolver);
|
transformer.setURIResolver(this.resolver);
|
||||||
// transformer.getUnderlyingController().setUnparsedTextURIResolver(resolver);
|
// transformer.getUnderlyingController().setUnparsedTextURIResolver(resolver);
|
||||||
if (parsedDocument != null) {
|
if (parsedDocument != null) {
|
||||||
transformer.setParameter(new QName("input-document"), parsedDocument);
|
transformer.setParameter(new QName("input-document"), parsedDocument);
|
||||||
|
|
@ -94,13 +201,13 @@ public class CreateReportAction implements CheckAction {
|
||||||
transformer.transform();
|
transformer.transform();
|
||||||
results.setReport(destination.getXdmNode());
|
results.setReport(destination.getXdmNode());
|
||||||
|
|
||||||
} catch (final SaxonApiException | SAXException e) {
|
} catch (final SaxonApiException | SAXException | JAXBException e) {
|
||||||
throw new IllegalStateException("Can not create final report", e);
|
throw new IllegalStateException("Can not create final report", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static XdmNode createErrorInformation(final Collection<XMLSyntaxError> errors) throws SaxonApiException, SAXException {
|
private XdmNode createErrorInformation(final Collection<XMLSyntaxError> errors) throws SaxonApiException, SAXException {
|
||||||
final BuildingContentHandler contentHandler = ObjectFactory.createProcessor().newDocumentBuilder().newBuildingContentHandler();
|
final BuildingContentHandler contentHandler = this.processor.newDocumentBuilder().newBuildingContentHandler();
|
||||||
contentHandler.startDocument();
|
contentHandler.startDocument();
|
||||||
contentHandler.startElement(EngineInformation.getFrameworkNamespace(), ERROR_MESSAGE_ELEMENT, ERROR_MESSAGE_ELEMENT,
|
contentHandler.startElement(EngineInformation.getFrameworkNamespace(), ERROR_MESSAGE_ELEMENT, ERROR_MESSAGE_ELEMENT,
|
||||||
new AttributesImpl());
|
new AttributesImpl());
|
||||||
|
|
|
||||||
|
|
@ -27,13 +27,13 @@ import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import de.kosit.validationtool.api.Input;
|
import de.kosit.validationtool.api.Input;
|
||||||
import de.kosit.validationtool.impl.ObjectFactory;
|
|
||||||
import de.kosit.validationtool.impl.model.Result;
|
import de.kosit.validationtool.impl.model.Result;
|
||||||
import de.kosit.validationtool.model.reportInput.ValidationResultsWellformedness;
|
import de.kosit.validationtool.model.reportInput.ValidationResultsWellformedness;
|
||||||
import de.kosit.validationtool.model.reportInput.XMLSyntaxError;
|
import de.kosit.validationtool.model.reportInput.XMLSyntaxError;
|
||||||
import de.kosit.validationtool.model.reportInput.XMLSyntaxErrorSeverity;
|
import de.kosit.validationtool.model.reportInput.XMLSyntaxErrorSeverity;
|
||||||
|
|
||||||
import net.sf.saxon.s9api.DocumentBuilder;
|
import net.sf.saxon.s9api.DocumentBuilder;
|
||||||
|
import net.sf.saxon.s9api.Processor;
|
||||||
import net.sf.saxon.s9api.SaxonApiException;
|
import net.sf.saxon.s9api.SaxonApiException;
|
||||||
import net.sf.saxon.s9api.XdmNode;
|
import net.sf.saxon.s9api.XdmNode;
|
||||||
|
|
||||||
|
|
@ -46,6 +46,7 @@ import net.sf.saxon.s9api.XdmNode;
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class DocumentParseAction implements CheckAction {
|
public class DocumentParseAction implements CheckAction {
|
||||||
|
|
||||||
|
private final Processor processor;
|
||||||
/**
|
/**
|
||||||
* Parsed und überprüft ein übergebenes Dokument darauf ob es well-formed ist. Dies stellt den ersten
|
* Parsed und überprüft ein übergebenes Dokument darauf ob es well-formed ist. Dies stellt den ersten
|
||||||
* Verarbeitungsschritt des Prüf-Tools dar. Diese Funktion verzichtet explizit auf die Validierung gegenüber einem
|
* Verarbeitungsschritt des Prüf-Tools dar. Diese Funktion verzichtet explizit auf die Validierung gegenüber einem
|
||||||
|
|
@ -54,13 +55,13 @@ public class DocumentParseAction implements CheckAction {
|
||||||
* @param content ein Dokument
|
* @param content ein Dokument
|
||||||
* @return Ergebnis des Parsings inklusive etwaiger Fehler
|
* @return Ergebnis des Parsings inklusive etwaiger Fehler
|
||||||
*/
|
*/
|
||||||
public static Result<XdmNode, XMLSyntaxError> parseDocument(final Input content) {
|
public Result<XdmNode, XMLSyntaxError> parseDocument(final Input content) {
|
||||||
if (content == null) {
|
if (content == null) {
|
||||||
throw new IllegalArgumentException("Input may not be null");
|
throw new IllegalArgumentException("Input may not be null");
|
||||||
}
|
}
|
||||||
Result<XdmNode, XMLSyntaxError> result;
|
Result<XdmNode, XMLSyntaxError> result;
|
||||||
try {
|
try {
|
||||||
final DocumentBuilder builder = ObjectFactory.createProcessor().newDocumentBuilder();
|
final DocumentBuilder builder = this.processor.newDocumentBuilder();
|
||||||
builder.setLineNumbering(true);
|
builder.setLineNumbering(true);
|
||||||
final XdmNode doc = builder.build(content.getSource());
|
final XdmNode doc = builder.build(content.getSource());
|
||||||
result = new Result<>(doc, Collections.emptyList());
|
result = new Result<>(doc, Collections.emptyList());
|
||||||
|
|
|
||||||
|
|
@ -36,12 +36,13 @@ import org.xml.sax.SAXException;
|
||||||
|
|
||||||
import lombok.AccessLevel;
|
import lombok.AccessLevel;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import de.kosit.validationtool.api.Input;
|
import de.kosit.validationtool.api.Input;
|
||||||
|
import de.kosit.validationtool.api.ResolvingConfigurationStrategy;
|
||||||
import de.kosit.validationtool.impl.CollectingErrorEventHandler;
|
import de.kosit.validationtool.impl.CollectingErrorEventHandler;
|
||||||
import de.kosit.validationtool.impl.ObjectFactory;
|
|
||||||
import de.kosit.validationtool.impl.Scenario;
|
import de.kosit.validationtool.impl.Scenario;
|
||||||
import de.kosit.validationtool.impl.input.AbstractInput;
|
import de.kosit.validationtool.impl.input.AbstractInput;
|
||||||
import de.kosit.validationtool.impl.model.Result;
|
import de.kosit.validationtool.impl.model.Result;
|
||||||
|
|
@ -49,6 +50,7 @@ import de.kosit.validationtool.model.reportInput.CreateReportInput;
|
||||||
import de.kosit.validationtool.model.reportInput.ValidationResultsXmlSchema;
|
import de.kosit.validationtool.model.reportInput.ValidationResultsXmlSchema;
|
||||||
import de.kosit.validationtool.model.reportInput.XMLSyntaxError;
|
import de.kosit.validationtool.model.reportInput.XMLSyntaxError;
|
||||||
|
|
||||||
|
import net.sf.saxon.s9api.Processor;
|
||||||
import net.sf.saxon.s9api.SaxonApiException;
|
import net.sf.saxon.s9api.SaxonApiException;
|
||||||
import net.sf.saxon.s9api.Serializer;
|
import net.sf.saxon.s9api.Serializer;
|
||||||
import net.sf.saxon.s9api.XdmNode;
|
import net.sf.saxon.s9api.XdmNode;
|
||||||
|
|
@ -67,16 +69,20 @@ import net.sf.saxon.s9api.XdmNode;
|
||||||
* @author Andreas Penski
|
* @author Andreas Penski
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
|
@RequiredArgsConstructor
|
||||||
public class SchemaValidationAction implements CheckAction {
|
public class SchemaValidationAction implements CheckAction {
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
private static class ByteArraySerializedDocument implements SerializedDocument {
|
private static class ByteArraySerializedDocument implements SerializedDocument {
|
||||||
|
|
||||||
private byte[] bytes;
|
private byte[] bytes;
|
||||||
|
|
||||||
|
private final Processor processor;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void serialize(final XdmNode node) throws SaxonApiException, IOException {
|
public void serialize(final XdmNode node) throws SaxonApiException, IOException {
|
||||||
try ( final ByteArrayOutputStream out = new ByteArrayOutputStream() ) {
|
try ( final ByteArrayOutputStream out = new ByteArrayOutputStream() ) {
|
||||||
final Serializer serializer = ObjectFactory.createProcessor().newSerializer();
|
final Serializer serializer = this.processor.newSerializer();
|
||||||
serializer.setOutputStream(out);
|
serializer.setOutputStream(out);
|
||||||
serializer.serializeNode(node);
|
serializer.serializeNode(node);
|
||||||
serializer.close();
|
serializer.close();
|
||||||
|
|
@ -97,16 +103,20 @@ public class SchemaValidationAction implements CheckAction {
|
||||||
|
|
||||||
private static class FileSerializedDocument implements SerializedDocument {
|
private static class FileSerializedDocument implements SerializedDocument {
|
||||||
|
|
||||||
|
|
||||||
private final Path file;
|
private final Path file;
|
||||||
|
|
||||||
FileSerializedDocument() throws IOException {
|
private final Processor processor;
|
||||||
|
|
||||||
|
FileSerializedDocument(final Processor processor) throws IOException {
|
||||||
this.file = Files.createTempFile("validator", ".xml");
|
this.file = Files.createTempFile("validator", ".xml");
|
||||||
|
this.processor = processor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void serialize(final XdmNode node) throws SaxonApiException, IOException {
|
public void serialize(final XdmNode node) throws SaxonApiException, IOException {
|
||||||
try ( final OutputStream out = Files.newOutputStream(this.file) ) {
|
try ( final OutputStream out = Files.newOutputStream(this.file) ) {
|
||||||
final Serializer serializer = ObjectFactory.createProcessor().newSerializer();
|
final Serializer serializer = this.processor.newSerializer();
|
||||||
serializer.setOutputStream(out);
|
serializer.setOutputStream(out);
|
||||||
serializer.serializeNode(node);
|
serializer.serializeNode(node);
|
||||||
serializer.close();
|
serializer.close();
|
||||||
|
|
@ -128,6 +138,10 @@ public class SchemaValidationAction implements CheckAction {
|
||||||
|
|
||||||
private static final String LIMIT_PARAMETER = "schema.validation.inmem.limit";
|
private static final String LIMIT_PARAMETER = "schema.validation.inmem.limit";
|
||||||
|
|
||||||
|
private final ResolvingConfigurationStrategy factory;
|
||||||
|
|
||||||
|
private final Processor processor;
|
||||||
|
|
||||||
@Setter(AccessLevel.PACKAGE)
|
@Setter(AccessLevel.PACKAGE)
|
||||||
@Getter
|
@Getter
|
||||||
private long inMemoryLimit = Long.parseLong(System.getProperty(LIMIT_PARAMETER, BA_LIMIT.toString())) * FileUtils.ONE_MB;
|
private long inMemoryLimit = Long.parseLong(System.getProperty(LIMIT_PARAMETER, BA_LIMIT.toString())) * FileUtils.ONE_MB;
|
||||||
|
|
@ -137,7 +151,7 @@ public class SchemaValidationAction implements CheckAction {
|
||||||
final CollectingErrorEventHandler errorHandler = new CollectingErrorEventHandler();
|
final CollectingErrorEventHandler errorHandler = new CollectingErrorEventHandler();
|
||||||
try ( final SourceProvider validateInput = resolveSource(results) ) {
|
try ( final SourceProvider validateInput = resolveSource(results) ) {
|
||||||
|
|
||||||
final Validator validator = ObjectFactory.createValidator(scenario.getSchema());
|
final Validator validator = this.factory.createValidator(scenario.getSchema());
|
||||||
validator.setErrorHandler(errorHandler);
|
validator.setErrorHandler(errorHandler);
|
||||||
validator.validate(validateInput.getSource());
|
validator.validate(validateInput.getSource());
|
||||||
return new Result<>(!errorHandler.hasErrors(), errorHandler.getErrors());
|
return new Result<>(!errorHandler.hasErrors(), errorHandler.getErrors());
|
||||||
|
|
@ -180,9 +194,9 @@ public class SchemaValidationAction implements CheckAction {
|
||||||
private SerializedDocument serialize(final Input input, final XdmNode object) throws IOException, SaxonApiException {
|
private SerializedDocument serialize(final Input input, final XdmNode object) throws IOException, SaxonApiException {
|
||||||
final SerializedDocument doc;
|
final SerializedDocument doc;
|
||||||
if (input instanceof AbstractInput && ((AbstractInput) input).getLength() < getInMemoryLimit()) {
|
if (input instanceof AbstractInput && ((AbstractInput) input).getLength() < getInMemoryLimit()) {
|
||||||
doc = new ByteArraySerializedDocument();
|
doc = new ByteArraySerializedDocument(this.processor);
|
||||||
} else {
|
} else {
|
||||||
doc = new FileSerializedDocument();
|
doc = new FileSerializedDocument(this.processor);
|
||||||
}
|
}
|
||||||
doc.serialize(object);
|
doc.serialize(object);
|
||||||
return doc;
|
return doc;
|
||||||
|
|
|
||||||
|
|
@ -26,21 +26,19 @@ import javax.xml.transform.URIResolver;
|
||||||
import javax.xml.transform.dom.DOMSource;
|
import javax.xml.transform.dom.DOMSource;
|
||||||
|
|
||||||
import org.oclc.purl.dsdl.svrl.SchematronOutput;
|
import org.oclc.purl.dsdl.svrl.SchematronOutput;
|
||||||
import org.w3c.dom.Document;
|
|
||||||
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import de.kosit.validationtool.impl.CollectingErrorEventHandler;
|
import de.kosit.validationtool.impl.CollectingErrorEventHandler;
|
||||||
import de.kosit.validationtool.impl.ContentRepository;
|
|
||||||
import de.kosit.validationtool.impl.ConversionService;
|
import de.kosit.validationtool.impl.ConversionService;
|
||||||
import de.kosit.validationtool.impl.ObjectFactory;
|
|
||||||
import de.kosit.validationtool.impl.Scenario;
|
import de.kosit.validationtool.impl.Scenario;
|
||||||
import de.kosit.validationtool.model.reportInput.CreateReportInput;
|
import de.kosit.validationtool.model.reportInput.CreateReportInput;
|
||||||
import de.kosit.validationtool.model.reportInput.ValidationResultsSchematron;
|
import de.kosit.validationtool.model.reportInput.ValidationResultsSchematron;
|
||||||
|
|
||||||
import net.sf.saxon.s9api.DOMDestination;
|
import net.sf.saxon.dom.NodeOverNodeInfo;
|
||||||
import net.sf.saxon.s9api.SaxonApiException;
|
import net.sf.saxon.s9api.SaxonApiException;
|
||||||
|
import net.sf.saxon.s9api.XdmDestination;
|
||||||
import net.sf.saxon.s9api.XdmNode;
|
import net.sf.saxon.s9api.XdmNode;
|
||||||
import net.sf.saxon.s9api.XsltTransformer;
|
import net.sf.saxon.s9api.XsltTransformer;
|
||||||
|
|
||||||
|
|
@ -53,7 +51,7 @@ import net.sf.saxon.s9api.XsltTransformer;
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class SchematronValidationAction implements CheckAction {
|
public class SchematronValidationAction implements CheckAction {
|
||||||
|
|
||||||
private final ContentRepository repository;
|
private final URIResolver resolver;
|
||||||
|
|
||||||
private final ConversionService conversionService;
|
private final ConversionService conversionService;
|
||||||
|
|
||||||
|
|
@ -67,18 +65,19 @@ public class SchematronValidationAction implements CheckAction {
|
||||||
try {
|
try {
|
||||||
final XsltTransformer transformer = validation.getExecutable().load();
|
final XsltTransformer transformer = validation.getExecutable().load();
|
||||||
// resolving nur relative zum Repository
|
// resolving nur relative zum Repository
|
||||||
final URIResolver resolver = this.repository.createResolver();
|
transformer.setURIResolver(this.resolver);
|
||||||
transformer.setURIResolver(resolver);
|
|
||||||
final CollectingErrorEventHandler e = new CollectingErrorEventHandler();
|
final CollectingErrorEventHandler e = new CollectingErrorEventHandler();
|
||||||
transformer.setMessageListener(e);
|
transformer.setMessageListener(e);
|
||||||
|
|
||||||
final Document result = ObjectFactory.createDocumentBuilder(false).newDocument();
|
final XdmDestination result = new XdmDestination();
|
||||||
transformer.setDestination(new DOMDestination(result));
|
transformer.setDestination(result);
|
||||||
transformer.setInitialContextNode(document);
|
transformer.setInitialContextNode(document);
|
||||||
transformer.transform();
|
transformer.transform();
|
||||||
|
|
||||||
final ValidationResultsSchematron.Results r = new ValidationResultsSchematron.Results();
|
final ValidationResultsSchematron.Results r = new ValidationResultsSchematron.Results();
|
||||||
r.setSchematronOutput(this.conversionService.readDocument(new DOMSource(result), SchematronOutput.class));
|
r.setSchematronOutput(this.conversionService.readDocument(
|
||||||
|
new DOMSource(NodeOverNodeInfo.wrap(result.getXdmNode().getUnderlyingNode()).getOwnerDocument()),
|
||||||
|
SchematronOutput.class));
|
||||||
s.setResults(r);
|
s.setResults(r);
|
||||||
|
|
||||||
} catch (final SaxonApiException e) {
|
} catch (final SaxonApiException e) {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,108 @@
|
||||||
|
package de.kosit.validationtool.impl.xml;
|
||||||
|
|
||||||
|
import static java.lang.String.format;
|
||||||
|
|
||||||
|
import javax.xml.XMLConstants;
|
||||||
|
import javax.xml.validation.SchemaFactory;
|
||||||
|
import javax.xml.validation.Validator;
|
||||||
|
|
||||||
|
import org.xml.sax.SAXNotRecognizedException;
|
||||||
|
import org.xml.sax.SAXNotSupportedException;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import de.kosit.validationtool.api.ResolvingConfigurationStrategy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Andreas Penski
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public abstract class BaseResolvingStrategy implements ResolvingConfigurationStrategy {
|
||||||
|
|
||||||
|
protected static final String DISSALLOW_DOCTYPE_DECL_FEATURE = "http://apache.org/xml/features/disallow-doctype-decl";
|
||||||
|
|
||||||
|
protected static final String LOAD_EXTERNAL_DTD_FEATURE = "http://apache.org/xml/features/nonvalidating/load-external-dtd";
|
||||||
|
|
||||||
|
protected static final String FEATURE_SECURE_PROCESSING = "http://javax.xml.XMLConstants/feature/secure-processing";
|
||||||
|
|
||||||
|
private static final String ORACLE_XERCES_CLASS = "com.sun.org.apache.xerces.internal.impl.Constants";
|
||||||
|
|
||||||
|
public static void forceOpenJdkXmlImplementation() {
|
||||||
|
if (!isOpenJdkXmlImplementationAvailable()) {
|
||||||
|
throw new IllegalStateException("No OpenJDK version of XERCES found");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isOpenJdkXmlImplementationAvailable() {
|
||||||
|
try {
|
||||||
|
Class.forName(ORACLE_XERCES_CLASS);
|
||||||
|
return true;
|
||||||
|
} catch (final ClassNotFoundException e) {
|
||||||
|
log.warn("No oracle JDK version of XERCES found. Configured security features may not have any effect.");
|
||||||
|
log.warn("Please take care of XML security while checking your xml contents");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setProperty(final PropertySetter setter, final boolean lenient, final String errorMessage) {
|
||||||
|
try {
|
||||||
|
setter.apply();
|
||||||
|
} catch (final SAXNotRecognizedException | SAXNotSupportedException e) {
|
||||||
|
|
||||||
|
if (lenient) {
|
||||||
|
log.warn(errorMessage);
|
||||||
|
log.debug(e.getMessage(), e);
|
||||||
|
} else {
|
||||||
|
throw new IllegalStateException(errorMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void allowExternalSchema(final Validator validator, final String... scheme) {
|
||||||
|
allowExternalSchema(validator, false, scheme);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void allowExternalSchema(final SchemaFactory schemaFactory, final String... scheme) {
|
||||||
|
allowExternalSchema(schemaFactory, false, scheme);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void allowExternalSchema(final Validator validator, final boolean lenient, final String... schemes) {
|
||||||
|
final String schemeString = String.join(",", schemes);
|
||||||
|
setProperty(() -> validator.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, schemeString), lenient, format(
|
||||||
|
"Can set external schema access to schemes (%s). Maybe an unsupported JAXP implementation is used.", schemeString));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void allowExternalSchema(final SchemaFactory schemaFactory, final boolean lenient, final String... schemes) {
|
||||||
|
final String schemeString = String.join(",", schemes);
|
||||||
|
setProperty(() -> schemaFactory.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, schemeString), lenient, format(
|
||||||
|
"Can set external schema access to schemes (%s). Maybe an unsupported JAXP implementation is used.", schemeString));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void disableExternalEntities(final Validator validator) {
|
||||||
|
disableExternalEntities(validator, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void disableExternalEntities(final SchemaFactory schemaFactory) {
|
||||||
|
disableExternalEntities(schemaFactory, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void disableExternalEntities(final Validator validator, final boolean lenient) {
|
||||||
|
log.debug("Try to disable extern DTD access");
|
||||||
|
setProperty(() -> validator.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, ""), lenient,
|
||||||
|
"Can not disable external DTD access. Maybe an unsupported JAXP implementation is used.");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void disableExternalEntities(final SchemaFactory schemaFactory, final boolean lenient) {
|
||||||
|
log.debug("Try to disable extern DTD access");
|
||||||
|
setProperty(() -> schemaFactory.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, ""), lenient,
|
||||||
|
"Can not disable external DTD access. Maybe an unsupported JAXP implementation is used.");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
private interface PropertySetter {
|
||||||
|
|
||||||
|
void apply() throws SAXNotRecognizedException, SAXNotSupportedException;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package de.kosit.validationtool.impl;
|
package de.kosit.validationtool.impl.xml;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
|
|
@ -25,14 +25,13 @@ import java.io.Reader;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
|
||||||
import javax.xml.transform.Source;
|
import javax.xml.transform.Source;
|
||||||
|
import javax.xml.transform.TransformerException;
|
||||||
import javax.xml.transform.URIResolver;
|
import javax.xml.transform.URIResolver;
|
||||||
import javax.xml.transform.stream.StreamSource;
|
import javax.xml.transform.stream.StreamSource;
|
||||||
|
|
||||||
import lombok.AccessLevel;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
import net.sf.saxon.Configuration;
|
import net.sf.saxon.Configuration;
|
||||||
import net.sf.saxon.lib.UnparsedTextURIResolver;
|
|
||||||
import net.sf.saxon.trans.XPathException;
|
import net.sf.saxon.trans.XPathException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -41,24 +40,24 @@ import net.sf.saxon.trans.XPathException;
|
||||||
*
|
*
|
||||||
* @author Andreas Penski
|
* @author Andreas Penski
|
||||||
*/
|
*/
|
||||||
@RequiredArgsConstructor(access = AccessLevel.PACKAGE)
|
@RequiredArgsConstructor()
|
||||||
public class RelativeUriResolver implements URIResolver, UnparsedTextURIResolver {
|
public class RelativeUriResolver implements URIResolver {
|
||||||
|
|
||||||
/** the base uri */
|
/** the base uri */
|
||||||
private final URI baseUri;
|
private final URI baseUri;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Source resolve(final String href, final String base) {
|
public Source resolve(final String href, final String base) throws TransformerException {
|
||||||
final URI resolved = resolve(URI.create(href), URI.create(base));
|
final URI resolved = resolve(URI.create(href), URI.create(base));
|
||||||
if (isUnderBaseUri(resolved)) {
|
if (isUnderBaseUri(resolved)) {
|
||||||
try {
|
try {
|
||||||
return new StreamSource(resolved.toURL().openStream(), resolved.toASCIIString());
|
return new StreamSource(resolved.toURL().openStream(), resolved.toASCIIString());
|
||||||
} catch (final IOException e) {
|
} catch (final IOException e) {
|
||||||
|
|
||||||
throw new IllegalStateException(String.format("Can not resolve required %s", href), e);
|
throw new TransformerException(String.format("Can not resolve required %s", href), e);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalStateException(String
|
throw new TransformerException(String
|
||||||
.format("The resolved transformation artifact %s is not within the configured repository %s", resolved, this.baseUri));
|
.format("The resolved transformation artifact %s is not within the configured repository %s", resolved, this.baseUri));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -87,7 +86,7 @@ public class RelativeUriResolver implements URIResolver, UnparsedTextURIResolver
|
||||||
return r.startsWith(base);
|
return r.startsWith(base);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Reader resolve(final URI absoluteURI, final String encoding, final Configuration config) throws XPathException {
|
public Reader resolve(final URI absoluteURI, final String encoding, final Configuration config) throws XPathException {
|
||||||
if (isUnderBaseUri(absoluteURI)) {
|
if (isUnderBaseUri(absoluteURI)) {
|
||||||
try {
|
try {
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
package de.kosit.validationtool.impl.xml;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
|
||||||
|
import javax.xml.transform.URIResolver;
|
||||||
|
import javax.xml.validation.Schema;
|
||||||
|
import javax.xml.validation.SchemaFactory;
|
||||||
|
import javax.xml.validation.Validator;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import net.sf.saxon.s9api.Processor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @author Andreas Penski
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class StrictLocalResolvingStrategy extends StrictRelativeResolvingStrategy {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* e.g. don't allow any scheme
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SchemaFactory createSchemaFactory() {
|
||||||
|
final SchemaFactory schemaFactory = super.createSchemaFactory();
|
||||||
|
allowExternalSchema(schemaFactory, "file", "jar");
|
||||||
|
return schemaFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Processor createProcessor() {
|
||||||
|
return super.createProcessor();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public URIResolver createResolver(final URI repository) {
|
||||||
|
// intentionally return 'null', since all resolving is configured with the other objects
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Validator createValidator(final Schema schema) {
|
||||||
|
final Validator validator = super.createValidator(schema);
|
||||||
|
allowExternalSchema(validator, "file", "jar");
|
||||||
|
return validator;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,127 @@
|
||||||
|
package de.kosit.validationtool.impl.xml;
|
||||||
|
|
||||||
|
import java.io.Reader;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
import javax.xml.XMLConstants;
|
||||||
|
import javax.xml.transform.Result;
|
||||||
|
import javax.xml.transform.TransformerException;
|
||||||
|
import javax.xml.transform.URIResolver;
|
||||||
|
import javax.xml.validation.Schema;
|
||||||
|
import javax.xml.validation.SchemaFactory;
|
||||||
|
import javax.xml.validation.Validator;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
import net.sf.saxon.Configuration;
|
||||||
|
import net.sf.saxon.expr.XPathContext;
|
||||||
|
import net.sf.saxon.lib.CollectionFinder;
|
||||||
|
import net.sf.saxon.lib.Feature;
|
||||||
|
import net.sf.saxon.lib.FeatureKeys;
|
||||||
|
import net.sf.saxon.lib.OutputURIResolver;
|
||||||
|
import net.sf.saxon.lib.ResourceCollection;
|
||||||
|
import net.sf.saxon.lib.UnparsedTextURIResolver;
|
||||||
|
import net.sf.saxon.s9api.Processor;
|
||||||
|
import net.sf.saxon.trans.XPathException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Andreas Penski
|
||||||
|
*/
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class StrictRelativeResolvingStrategy extends BaseResolvingStrategy {
|
||||||
|
|
||||||
|
private static class SecureUriResolver implements CollectionFinder, OutputURIResolver, UnparsedTextURIResolver {
|
||||||
|
|
||||||
|
public static final String MESSAGE = "Configuration error. Resolving ist not allowed";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public OutputURIResolver newInstance() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Result resolve(final String href, final String base) throws TransformerException {
|
||||||
|
throw new IllegalStateException(MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close(final Result result) throws TransformerException {
|
||||||
|
throw new IllegalStateException(MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Reader resolve(final URI absoluteURI, final String encoding, final Configuration config) throws XPathException {
|
||||||
|
throw new IllegalStateException(MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResourceCollection findCollection(final XPathContext context, final String collectionURI) throws XPathException {
|
||||||
|
throw new IllegalStateException(MESSAGE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* e.g. don't allow any scheme
|
||||||
|
*/
|
||||||
|
private static final String EMPTY_SCHEME = "";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SchemaFactory createSchemaFactory() {
|
||||||
|
final SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
|
||||||
|
disableExternalEntities(sf);
|
||||||
|
allowExternalSchema(sf, "file");
|
||||||
|
return sf;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Processor createProcessor() {
|
||||||
|
final Processor processor = new Processor(false);
|
||||||
|
// verhindere global im Prinzip alle resolving strategien
|
||||||
|
final SecureUriResolver resolver = new SecureUriResolver();
|
||||||
|
processor.getUnderlyingConfiguration().setCollectionFinder(resolver);
|
||||||
|
processor.getUnderlyingConfiguration().setOutputURIResolver(resolver);
|
||||||
|
processor.getUnderlyingConfiguration().setUnparsedTextURIResolver(resolver);
|
||||||
|
|
||||||
|
// grundsätzlich Feature-konfiguration:
|
||||||
|
processor.setConfigurationProperty(Feature.DTD_VALIDATION, false);
|
||||||
|
processor.setConfigurationProperty(Feature.ENTITY_RESOLVER_CLASS, "");
|
||||||
|
processor.setConfigurationProperty(Feature.XINCLUDE, false);
|
||||||
|
processor.setConfigurationProperty(Feature.ALLOW_EXTERNAL_FUNCTIONS, false);
|
||||||
|
|
||||||
|
// Konfiguration des zu verwendenden Parsers, wenn Saxon selbst einen erzeugen muss, bspw. beim XSL parsen
|
||||||
|
processor.setConfigurationProperty(FeatureKeys.XML_PARSER_FEATURE + encode(FEATURE_SECURE_PROCESSING), true);
|
||||||
|
processor.setConfigurationProperty(FeatureKeys.XML_PARSER_FEATURE + encode(DISSALLOW_DOCTYPE_DECL_FEATURE), true);
|
||||||
|
processor.setConfigurationProperty(FeatureKeys.XML_PARSER_FEATURE + encode(LOAD_EXTERNAL_DTD_FEATURE), false);
|
||||||
|
return processor;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String encode(final String input) {
|
||||||
|
try {
|
||||||
|
return URLEncoder.encode(input, StandardCharsets.UTF_8.name());
|
||||||
|
} catch (final UnsupportedEncodingException e) {
|
||||||
|
throw new IllegalStateException("Error encoding property while initializing saxon", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public URIResolver createResolver(final URI repositoryURI) {
|
||||||
|
return new RelativeUriResolver(repositoryURI);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Validator createValidator(final Schema schema) {
|
||||||
|
if (schema == null) {
|
||||||
|
throw new IllegalArgumentException("No schema supplied. Can not create validator");
|
||||||
|
}
|
||||||
|
forceOpenJdkXmlImplementation();
|
||||||
|
final Validator validator = schema.newValidator();
|
||||||
|
disableExternalEntities(validator);
|
||||||
|
allowExternalSchema(validator, "file" /* allow nothing external */);
|
||||||
|
return validator;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -31,7 +31,7 @@ import org.junit.Test;
|
||||||
import de.kosit.validationtool.api.InputFactory;
|
import de.kosit.validationtool.api.InputFactory;
|
||||||
import de.kosit.validationtool.cmd.assertions.Assertions;
|
import de.kosit.validationtool.cmd.assertions.Assertions;
|
||||||
import de.kosit.validationtool.impl.Helper;
|
import de.kosit.validationtool.impl.Helper;
|
||||||
import de.kosit.validationtool.impl.ObjectFactory;
|
import de.kosit.validationtool.impl.TestObjectFactory;
|
||||||
import de.kosit.validationtool.impl.tasks.CheckAction;
|
import de.kosit.validationtool.impl.tasks.CheckAction;
|
||||||
import de.kosit.validationtool.model.reportInput.CreateReportInput;
|
import de.kosit.validationtool.model.reportInput.CreateReportInput;
|
||||||
|
|
||||||
|
|
@ -52,15 +52,15 @@ public class CheckAssertionActionTest {
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() throws IOException {
|
public void setup() throws IOException {
|
||||||
commandLine = new CommandLine();
|
this.commandLine = new CommandLine();
|
||||||
commandLine.activate();
|
this.commandLine.activate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEmptyInput() {
|
public void testEmptyInput() {
|
||||||
CheckAssertionAction a = new CheckAssertionAction(new Assertions(), ObjectFactory.createProcessor());
|
final CheckAssertionAction a = new CheckAssertionAction(new Assertions(), TestObjectFactory.createProcessor());
|
||||||
a.check(new CheckAction.Bag(InputFactory.read(SAMPLE), new CreateReportInput()));
|
a.check(new CheckAction.Bag(InputFactory.read(SAMPLE), new CreateReportInput()));
|
||||||
assertThat(commandLine.getErrorOutput()).contains("Can not find assertions for");
|
assertThat(this.commandLine.getErrorOutput()).contains("Can not find assertions for");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -69,9 +69,9 @@ public class CheckAssertionActionTest {
|
||||||
bag.setReport(Helper.load(SAMPLE_REPORT));
|
bag.setReport(Helper.load(SAMPLE_REPORT));
|
||||||
|
|
||||||
final Assertions assertions = Helper.load(SAMPLE_ASSERTIONS, Assertions.class);
|
final Assertions assertions = Helper.load(SAMPLE_ASSERTIONS, Assertions.class);
|
||||||
CheckAssertionAction a = new CheckAssertionAction(assertions, ObjectFactory.createProcessor());
|
final CheckAssertionAction a = new CheckAssertionAction(assertions, TestObjectFactory.createProcessor());
|
||||||
a.check(bag);
|
a.check(bag);
|
||||||
|
|
||||||
assertThat(commandLine.getErrorOutput()).contains("Assertion mismatch");
|
assertThat(this.commandLine.getErrorOutput()).contains("Assertion mismatch");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -105,12 +105,13 @@ public class CommandlineApplicationTest {
|
||||||
final String[] args = new String[] { "-s", Paths.get(Simple.SCENARIOS).toString(), Paths.get(Simple.NOT_EXISTING).toString() };
|
final String[] args = new String[] { "-s", Paths.get(Simple.SCENARIOS).toString(), Paths.get(Simple.NOT_EXISTING).toString() };
|
||||||
CommandLineApplication.mainProgram(args);
|
CommandLineApplication.mainProgram(args);
|
||||||
assertThat(this.commandLine.getErrorOutput()).isNotEmpty();
|
assertThat(this.commandLine.getErrorOutput()).isNotEmpty();
|
||||||
assertThat(this.commandLine.getErrorOutput()).contains("Can not load schema from sources");
|
assertThat(this.commandLine.getErrorOutput()).contains("Can not resolve");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNotExistingTestTarget() {
|
public void testNotExistingTestTarget() {
|
||||||
final String[] args = new String[] { "-s", Paths.get(Simple.SCENARIOS).toString(), "-r", Paths.get(Simple.REPOSITORY).toString(),
|
final String[] args = new String[] { "-s", Paths.get(Simple.SCENARIOS).toString(), "-r",
|
||||||
|
Paths.get(Simple.REPOSITORY_URI).toString(),
|
||||||
Paths.get(Simple.NOT_EXISTING).toString() };
|
Paths.get(Simple.NOT_EXISTING).toString() };
|
||||||
CommandLineApplication.mainProgram(args);
|
CommandLineApplication.mainProgram(args);
|
||||||
assertThat(this.commandLine.getErrorOutput()).isNotEmpty();
|
assertThat(this.commandLine.getErrorOutput()).isNotEmpty();
|
||||||
|
|
@ -119,7 +120,8 @@ public class CommandlineApplicationTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testValidMinimalConfiguration() {
|
public void testValidMinimalConfiguration() {
|
||||||
final String[] args = new String[] { "-s", Paths.get(Simple.SCENARIOS).toString(), "-r", Paths.get(Simple.REPOSITORY).toString(),
|
final String[] args = new String[] { "-s", Paths.get(Simple.SCENARIOS).toString(), "-r",
|
||||||
|
Paths.get(Simple.REPOSITORY_URI).toString(),
|
||||||
Paths.get(Simple.SIMPLE_VALID).toString() };
|
Paths.get(Simple.SIMPLE_VALID).toString() };
|
||||||
CommandLineApplication.mainProgram(args);
|
CommandLineApplication.mainProgram(args);
|
||||||
assertThat(this.commandLine.getErrorOutput()).contains(RESULT_OUTPUT);
|
assertThat(this.commandLine.getErrorOutput()).contains(RESULT_OUTPUT);
|
||||||
|
|
@ -128,7 +130,7 @@ public class CommandlineApplicationTest {
|
||||||
@Test
|
@Test
|
||||||
public void testValidMultipleInput() {
|
public void testValidMultipleInput() {
|
||||||
final String[] args = new String[] { "-s", Paths.get(Simple.SCENARIOS).toString(), "-o", this.output.toString(), "-r",
|
final String[] args = new String[] { "-s", Paths.get(Simple.SCENARIOS).toString(), "-o", this.output.toString(), "-r",
|
||||||
Paths.get(Simple.REPOSITORY).toString(), Paths.get(Simple.SIMPLE_VALID).toString(), Paths.get(Simple.FOO).toString() };
|
Paths.get(Simple.REPOSITORY_URI).toString(), Paths.get(Simple.SIMPLE_VALID).toString(), Paths.get(Simple.FOO).toString() };
|
||||||
CommandLineApplication.mainProgram(args);
|
CommandLineApplication.mainProgram(args);
|
||||||
assertThat(this.commandLine.getErrorOutput()).contains("Processing 2 object(s) completed");
|
assertThat(this.commandLine.getErrorOutput()).contains("Processing 2 object(s) completed");
|
||||||
}
|
}
|
||||||
|
|
@ -136,7 +138,7 @@ public class CommandlineApplicationTest {
|
||||||
@Test
|
@Test
|
||||||
public void testValidDirectoryInput() {
|
public void testValidDirectoryInput() {
|
||||||
final String[] args = new String[] { "-s", Paths.get(Simple.SCENARIOS).toString(), "-o", this.output.toString(), "-r",
|
final String[] args = new String[] { "-s", Paths.get(Simple.SCENARIOS).toString(), "-o", this.output.toString(), "-r",
|
||||||
Paths.get(Simple.REPOSITORY).toString(), Paths.get(Simple.EXAMPLES).toString() };
|
Paths.get(Simple.REPOSITORY_URI).toString(), Paths.get(Simple.EXAMPLES).toString() };
|
||||||
CommandLineApplication.mainProgram(args);
|
CommandLineApplication.mainProgram(args);
|
||||||
assertThat(this.commandLine.getErrorOutput()).contains("Processing 6 object(s) completed");
|
assertThat(this.commandLine.getErrorOutput()).contains("Processing 6 object(s) completed");
|
||||||
}
|
}
|
||||||
|
|
@ -145,7 +147,7 @@ public class CommandlineApplicationTest {
|
||||||
public void testValidOutputConfiguration() throws IOException {
|
public void testValidOutputConfiguration() throws IOException {
|
||||||
|
|
||||||
final String[] args = new String[] { "-s", Paths.get(Simple.SCENARIOS).toString(), "-o", this.output.toString(), "-r",
|
final String[] args = new String[] { "-s", Paths.get(Simple.SCENARIOS).toString(), "-o", this.output.toString(), "-r",
|
||||||
Paths.get(Simple.REPOSITORY).toString(), Paths.get(Simple.SIMPLE_VALID).toString() };
|
Paths.get(Simple.REPOSITORY_URI).toString(), Paths.get(Simple.SIMPLE_VALID).toString() };
|
||||||
CommandLineApplication.mainProgram(args);
|
CommandLineApplication.mainProgram(args);
|
||||||
assertThat(this.commandLine.getErrorOutput()).contains(RESULT_OUTPUT);
|
assertThat(this.commandLine.getErrorOutput()).contains(RESULT_OUTPUT);
|
||||||
assertThat(this.output).exists();
|
assertThat(this.output).exists();
|
||||||
|
|
@ -155,7 +157,8 @@ public class CommandlineApplicationTest {
|
||||||
@Test
|
@Test
|
||||||
public void testNoInput() {
|
public void testNoInput() {
|
||||||
// assertThat(output).doesNotExist();
|
// assertThat(output).doesNotExist();
|
||||||
final String[] args = new String[] { "-s", Paths.get(Simple.SCENARIOS).toString(), "-r", Paths.get(Simple.REPOSITORY).toString(), };
|
final String[] args = new String[] { "-s", Paths.get(Simple.SCENARIOS).toString(), "-r",
|
||||||
|
Paths.get(Simple.REPOSITORY_URI).toString(), };
|
||||||
CommandLineApplication.mainProgram(args);
|
CommandLineApplication.mainProgram(args);
|
||||||
checkForHelp(this.commandLine.getOutputLines());
|
checkForHelp(this.commandLine.getOutputLines());
|
||||||
}
|
}
|
||||||
|
|
@ -164,7 +167,7 @@ public class CommandlineApplicationTest {
|
||||||
public void testPrint() {
|
public void testPrint() {
|
||||||
|
|
||||||
final String[] args = new String[] { "-s", Paths.get(Simple.SCENARIOS).toString(), "-p", "-r",
|
final String[] args = new String[] { "-s", Paths.get(Simple.SCENARIOS).toString(), "-p", "-r",
|
||||||
Paths.get(Simple.REPOSITORY).toString(), "-o", this.output.toString(), Paths.get(Simple.SIMPLE_VALID).toString() };
|
Paths.get(Simple.REPOSITORY_URI).toString(), "-o", this.output.toString(), Paths.get(Simple.SIMPLE_VALID).toString() };
|
||||||
CommandLineApplication.mainProgram(args);
|
CommandLineApplication.mainProgram(args);
|
||||||
assertThat(this.commandLine.getErrorOutput()).contains(RESULT_OUTPUT);
|
assertThat(this.commandLine.getErrorOutput()).contains(RESULT_OUTPUT);
|
||||||
assertThat(this.commandLine.getOutputLines().get(0)).contains("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
|
assertThat(this.commandLine.getOutputLines().get(0)).contains("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
|
||||||
|
|
@ -174,7 +177,7 @@ public class CommandlineApplicationTest {
|
||||||
public void testHtmlExtraktion() throws IOException {
|
public void testHtmlExtraktion() throws IOException {
|
||||||
final String[] args = new String[] { "-s", Paths.get(Simple.SCENARIOS).toString(), "-h", "-o",
|
final String[] args = new String[] { "-s", Paths.get(Simple.SCENARIOS).toString(), "-h", "-o",
|
||||||
this.output.toAbsolutePath().toString(),
|
this.output.toAbsolutePath().toString(),
|
||||||
"-r", Paths.get(Simple.REPOSITORY).toString(), Paths.get(Simple.SIMPLE_VALID).toString() };
|
"-r", Paths.get(Simple.REPOSITORY_URI).toString(), Paths.get(Simple.SIMPLE_VALID).toString() };
|
||||||
CommandLineApplication.mainProgram(args);
|
CommandLineApplication.mainProgram(args);
|
||||||
assertThat(this.commandLine.getErrorOutput()).contains(RESULT_OUTPUT);
|
assertThat(this.commandLine.getErrorOutput()).contains(RESULT_OUTPUT);
|
||||||
assertThat(Files.list(this.output).filter(f -> f.toString().endsWith(".html")).count()).isGreaterThan(0);
|
assertThat(Files.list(this.output).filter(f -> f.toString().endsWith(".html")).count()).isGreaterThan(0);
|
||||||
|
|
@ -183,8 +186,8 @@ public class CommandlineApplicationTest {
|
||||||
@Test
|
@Test
|
||||||
public void testAssertionsExtraktion() {
|
public void testAssertionsExtraktion() {
|
||||||
final String[] args = new String[] { "-d", "-s", Paths.get(Simple.SCENARIOS).toString(), "-r",
|
final String[] args = new String[] { "-d", "-s", Paths.get(Simple.SCENARIOS).toString(), "-r",
|
||||||
Paths.get(Simple.REPOSITORY).toString(), "-o", this.output.toString(), "-c", Paths.get(ASSERTIONS).toString(),
|
Paths.get(Simple.REPOSITORY_URI).toString(), "-o", this.output.toString(), "-c", Paths.get(ASSERTIONS).toString(),
|
||||||
Paths.get(Simple.REPOSITORY).toString(),
|
Paths.get(Simple.REPOSITORY_URI).toString(),
|
||||||
Paths.get(Simple.SIMPLE_VALID).toString() };
|
Paths.get(Simple.SIMPLE_VALID).toString() };
|
||||||
CommandLineApplication.mainProgram(args);
|
CommandLineApplication.mainProgram(args);
|
||||||
assertThat(this.commandLine.getErrorOutput()).contains(RESULT_OUTPUT);
|
assertThat(this.commandLine.getErrorOutput()).contains(RESULT_OUTPUT);
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ import org.junit.Test;
|
||||||
import de.kosit.validationtool.api.InputFactory;
|
import de.kosit.validationtool.api.InputFactory;
|
||||||
import de.kosit.validationtool.impl.Helper;
|
import de.kosit.validationtool.impl.Helper;
|
||||||
import de.kosit.validationtool.impl.Helper.Simple;
|
import de.kosit.validationtool.impl.Helper.Simple;
|
||||||
|
import de.kosit.validationtool.impl.TestObjectFactory;
|
||||||
import de.kosit.validationtool.impl.tasks.CheckAction;
|
import de.kosit.validationtool.impl.tasks.CheckAction;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -51,7 +52,7 @@ public class ExtractHtmlActionTest {
|
||||||
@Before
|
@Before
|
||||||
public void setup() throws IOException {
|
public void setup() throws IOException {
|
||||||
this.tmpDirectory = Files.createTempDirectory("checktool");
|
this.tmpDirectory = Files.createTempDirectory("checktool");
|
||||||
this.action = new ExtractHtmlContentAction(Helper.loadTestRepository(), this.tmpDirectory);
|
this.action = new ExtractHtmlContentAction(TestObjectFactory.createProcessor(), this.tmpDirectory);
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ import org.junit.Test;
|
||||||
import de.kosit.validationtool.api.InputFactory;
|
import de.kosit.validationtool.api.InputFactory;
|
||||||
import de.kosit.validationtool.impl.Helper;
|
import de.kosit.validationtool.impl.Helper;
|
||||||
import de.kosit.validationtool.impl.Helper.Simple;
|
import de.kosit.validationtool.impl.Helper.Simple;
|
||||||
|
import de.kosit.validationtool.impl.TestObjectFactory;
|
||||||
import de.kosit.validationtool.impl.tasks.CheckAction;
|
import de.kosit.validationtool.impl.tasks.CheckAction;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -46,7 +47,7 @@ public class PrintReportActionTest {
|
||||||
public void setup() {
|
public void setup() {
|
||||||
this.commandLine = new CommandLine();
|
this.commandLine = new CommandLine();
|
||||||
this.commandLine.activate();
|
this.commandLine.activate();
|
||||||
this.action = new PrintReportAction();
|
this.action = new PrintReportAction(TestObjectFactory.createProcessor());
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ import org.junit.Test;
|
||||||
import de.kosit.validationtool.api.InputFactory;
|
import de.kosit.validationtool.api.InputFactory;
|
||||||
import de.kosit.validationtool.impl.Helper;
|
import de.kosit.validationtool.impl.Helper;
|
||||||
import de.kosit.validationtool.impl.Helper.Simple;
|
import de.kosit.validationtool.impl.Helper.Simple;
|
||||||
|
import de.kosit.validationtool.impl.TestObjectFactory;
|
||||||
import de.kosit.validationtool.impl.tasks.CheckAction;
|
import de.kosit.validationtool.impl.tasks.CheckAction;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -49,7 +50,7 @@ public class SerializeReportActionTest {
|
||||||
@Before
|
@Before
|
||||||
public void setup() throws IOException {
|
public void setup() throws IOException {
|
||||||
this.tmpDirectory = Files.createTempDirectory("checktool");
|
this.tmpDirectory = Files.createTempDirectory("checktool");
|
||||||
this.action = new SerializeReportAction(this.tmpDirectory);
|
this.action = new SerializeReportAction(this.tmpDirectory, TestObjectFactory.createProcessor());
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
package de.kosit.validationtool.config;
|
||||||
|
|
||||||
|
import static de.kosit.validationtool.config.ConfigurationBuilder.fallback;
|
||||||
|
import static de.kosit.validationtool.config.ConfigurationBuilder.report;
|
||||||
|
import static de.kosit.validationtool.config.ConfigurationBuilder.scenario;
|
||||||
|
import static de.kosit.validationtool.config.ConfigurationBuilder.schema;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import de.kosit.validationtool.api.Configuration;
|
||||||
|
import de.kosit.validationtool.api.InputFactory;
|
||||||
|
import de.kosit.validationtool.api.Result;
|
||||||
|
import de.kosit.validationtool.impl.DefaultCheck;
|
||||||
|
import de.kosit.validationtool.impl.Helper.Simple;
|
||||||
|
import de.kosit.validationtool.impl.ResolvingMode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Andreas Penski
|
||||||
|
*/
|
||||||
|
public class SimpleConfigTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSimpleWithApi() {
|
||||||
|
//@formatter:off
|
||||||
|
final Configuration config =
|
||||||
|
Configuration.create().name("Simple-API")
|
||||||
|
.with(scenario("simple")
|
||||||
|
.validate(schema("Sample Schema").schemaLocation(URI.create("simple.xsd")))
|
||||||
|
.with(report("Report für eRechnung").source("report.xsl"))
|
||||||
|
.acceptWith("count(//test:rejected) = 0")
|
||||||
|
.declareNamespace("cri", "http://www.xoev.de/de/validator/framework/1/createreportinput")
|
||||||
|
.declareNamespace("rpt", "http://validator.kosit.de/test-report")
|
||||||
|
.declareNamespace("test", "http://validator.kosit.de/test-sample")
|
||||||
|
.match("/test:simple")
|
||||||
|
// .description("awesome api")
|
||||||
|
)
|
||||||
|
.with(fallback().name("default").source("report.xsl"))
|
||||||
|
|
||||||
|
.resolvingMode(ResolvingMode.STRICT_RELATIVE)
|
||||||
|
.useRepository(Simple.REPOSITORY_URI).build();
|
||||||
|
//@formatter:on
|
||||||
|
final DefaultCheck check = new DefaultCheck(config);
|
||||||
|
final Result result = check.checkInput(InputFactory.read(Simple.SIMPLE_VALID));
|
||||||
|
assertThat(result).isNotNull();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -55,7 +55,7 @@ public class ContentRepositoryTest {
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() {
|
||||||
this.repository = new ContentRepository(ObjectFactory.createProcessor(), Simple.REPOSITORY);
|
this.repository = Simple.createContentRepository();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -114,7 +114,7 @@ public class ContentRepositoryTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void loadFromJar() throws URISyntaxException {
|
public void loadFromJar() throws URISyntaxException {
|
||||||
this.repository = new ContentRepository(ObjectFactory.createProcessor(), Helper.JAR_REPOSITORY.toURI());
|
this.repository = new ContentRepository(TestObjectFactory.createProcessor(), Helper.JAR_REPOSITORY.toURI(), null);
|
||||||
final XsltExecutable xsltExecutable = this.repository.loadXsltScript(URI.create("resources/eRechnung/report.xsl"));
|
final XsltExecutable xsltExecutable = this.repository.loadXsltScript(URI.create("resources/eRechnung/report.xsl"));
|
||||||
assertThat(xsltExecutable).isNotNull();
|
assertThat(xsltExecutable).isNotNull();
|
||||||
}
|
}
|
||||||
|
|
@ -136,7 +136,7 @@ public class ContentRepositoryTest {
|
||||||
|
|
||||||
// @Test
|
// @Test
|
||||||
// public void loadFromJar() throws URISyntaxException {
|
// public void loadFromJar() throws URISyntaxException {
|
||||||
// this.content = new ContentRepository(ObjectFactory.createProcessor(), Helper.JAR_REPOSITORY.toURI());
|
// this.content = new ContentRepository(TestObjectFactory.createProcessor(), Helper.JAR_REPOSITORY.toURI());
|
||||||
// this.repository = new ScenarioRepository(this.content);
|
// this.repository = new ScenarioRepository(this.content);
|
||||||
// final CheckConfiguration conf = new CheckConfiguration(
|
// final CheckConfiguration conf = new CheckConfiguration(
|
||||||
// ScenarioRepository.class.getClassLoader().getResource("xrechnung/scenarios.xml").toURI());
|
// ScenarioRepository.class.getClassLoader().getResource("xrechnung/scenarios.xml").toURI());
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,6 @@ package de.kosit.validationtool.impl;
|
||||||
|
|
||||||
import static org.assertj.core.api.Java6Assertions.assertThat;
|
import static org.assertj.core.api.Java6Assertions.assertThat;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
|
@ -54,8 +53,7 @@ public class ConversionServiceTest {
|
||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() {
|
||||||
this.service = new ConversionService();
|
this.service = new ConversionService();
|
||||||
this.repository = new ContentRepository(ObjectFactory.createProcessor(),
|
this.repository = Simple.createContentRepository();
|
||||||
new File("src/test/resources/examples/repository").toURI());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ public class DefaultCheckTest {
|
||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() {
|
||||||
final CheckConfiguration d = new CheckConfiguration(Simple.SCENARIOS);
|
final CheckConfiguration d = new CheckConfiguration(Simple.SCENARIOS);
|
||||||
d.setScenarioRepository(new File(Simple.REPOSITORY).toURI());
|
d.setScenarioRepository(new File(Simple.REPOSITORY_URI).toURI());
|
||||||
this.implementation = new DefaultCheck(d);
|
this.implementation = new DefaultCheck(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,6 @@ import org.junit.rules.ExpectedException;
|
||||||
|
|
||||||
import de.kosit.validationtool.impl.Helper.Simple;
|
import de.kosit.validationtool.impl.Helper.Simple;
|
||||||
import de.kosit.validationtool.impl.model.Result;
|
import de.kosit.validationtool.impl.model.Result;
|
||||||
import de.kosit.validationtool.impl.tasks.DocumentParseAction;
|
|
||||||
import de.kosit.validationtool.model.reportInput.XMLSyntaxError;
|
import de.kosit.validationtool.model.reportInput.XMLSyntaxError;
|
||||||
|
|
||||||
import net.sf.saxon.s9api.XdmNode;
|
import net.sf.saxon.s9api.XdmNode;
|
||||||
|
|
@ -45,7 +44,7 @@ public class DocumentParserTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSimple() {
|
public void testSimple() {
|
||||||
final Result<XdmNode, XMLSyntaxError> result = DocumentParseAction.parseDocument(read(Simple.SIMPLE_VALID));
|
final Result<XdmNode, XMLSyntaxError> result = Helper.parseDocument(read(Simple.SIMPLE_VALID));
|
||||||
assertThat(result).isNotNull();
|
assertThat(result).isNotNull();
|
||||||
assertThat(result.getObject()).isNotNull();
|
assertThat(result.getObject()).isNotNull();
|
||||||
assertThat(result.getErrors()).isEmpty();
|
assertThat(result.getErrors()).isEmpty();
|
||||||
|
|
@ -54,7 +53,7 @@ public class DocumentParserTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIllformed() {
|
public void testIllformed() {
|
||||||
final Result<XdmNode, XMLSyntaxError> result = DocumentParseAction.parseDocument(read(Simple.NOT_WELLFORMED));
|
final Result<XdmNode, XMLSyntaxError> result = Helper.parseDocument(read(Simple.NOT_WELLFORMED));
|
||||||
assertThat(result).isNotNull();
|
assertThat(result).isNotNull();
|
||||||
assertThat(result.getErrors()).isNotEmpty();
|
assertThat(result.getErrors()).isNotEmpty();
|
||||||
assertThat(result.getObject()).isNull();
|
assertThat(result.getObject()).isNull();
|
||||||
|
|
@ -64,7 +63,7 @@ public class DocumentParserTest {
|
||||||
@Test
|
@Test
|
||||||
public void testNullInput() {
|
public void testNullInput() {
|
||||||
this.exception.expect(IllegalArgumentException.class);
|
this.exception.expect(IllegalArgumentException.class);
|
||||||
DocumentParseAction.parseDocument(null);
|
Helper.parseDocument(null);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,12 @@ import javax.xml.transform.stream.StreamSource;
|
||||||
|
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
|
|
||||||
|
import de.kosit.validationtool.api.Input;
|
||||||
|
import de.kosit.validationtool.api.ResolvingConfigurationStrategy;
|
||||||
|
import de.kosit.validationtool.impl.model.Result;
|
||||||
|
import de.kosit.validationtool.impl.tasks.DocumentParseAction;
|
||||||
|
import de.kosit.validationtool.model.reportInput.XMLSyntaxError;
|
||||||
|
|
||||||
import net.sf.saxon.dom.NodeOverNodeInfo;
|
import net.sf.saxon.dom.NodeOverNodeInfo;
|
||||||
import net.sf.saxon.s9api.SaxonApiException;
|
import net.sf.saxon.s9api.SaxonApiException;
|
||||||
import net.sf.saxon.s9api.XdmNode;
|
import net.sf.saxon.s9api.XdmNode;
|
||||||
|
|
@ -61,7 +67,7 @@ public class Helper {
|
||||||
|
|
||||||
public static final URI SCENARIOS = ROOT.resolve("scenarios.xml");
|
public static final URI SCENARIOS = ROOT.resolve("scenarios.xml");
|
||||||
|
|
||||||
public static final URI REPOSITORY = ROOT.resolve("repository/");
|
public static final URI REPOSITORY_URI = ROOT.resolve("repository/");
|
||||||
|
|
||||||
public static final URI INVALID = ROOT.resolve("input/simple-invalid.xml");
|
public static final URI INVALID = ROOT.resolve("input/simple-invalid.xml");
|
||||||
|
|
||||||
|
|
@ -73,8 +79,16 @@ public class Helper {
|
||||||
|
|
||||||
public static final URI NOT_EXISTING = EXAMPLES_DIR.resolve("doesnotexist");
|
public static final URI NOT_EXISTING = EXAMPLES_DIR.resolve("doesnotexist");
|
||||||
|
|
||||||
public static final URI REPORT_XSL = REPOSITORY.resolve("report.xsl");
|
public static final URI REPORT_XSL = REPOSITORY_URI.resolve("report.xsl");
|
||||||
|
|
||||||
|
public static final ContentRepository createContentRepository() {
|
||||||
|
final ResolvingConfigurationStrategy strategy = ResolvingMode.STRICT_RELATIVE.getStrategy();
|
||||||
|
final ContentRepository rep = new ContentRepository(TestObjectFactory.createProcessor(), Simple.REPOSITORY_URI,
|
||||||
|
strategy.createResolver(Simple.REPOSITORY_URI));
|
||||||
|
rep.setResolvingConfigurationStrategy(strategy);
|
||||||
|
rep.setSchemaFactory(strategy.createSchemaFactory());
|
||||||
|
return rep;
|
||||||
|
}
|
||||||
public static URI getSchemaLocation() {
|
public static URI getSchemaLocation() {
|
||||||
return ROOT.resolve("repository/simple.xsd");
|
return ROOT.resolve("repository/simple.xsd");
|
||||||
}
|
}
|
||||||
|
|
@ -118,7 +132,7 @@ public class Helper {
|
||||||
*/
|
*/
|
||||||
public static XdmNode load(final URL url) {
|
public static XdmNode load(final URL url) {
|
||||||
try ( final InputStream input = url.openStream() ) {
|
try ( final InputStream input = url.openStream() ) {
|
||||||
return ObjectFactory.createProcessor().newDocumentBuilder().build(new StreamSource(input));
|
return TestObjectFactory.createProcessor().newDocumentBuilder().build(new StreamSource(input));
|
||||||
} catch (final SaxonApiException | IOException e) {
|
} catch (final SaxonApiException | IOException e) {
|
||||||
throw new IllegalStateException("Fehler beim Laden der XML-Datei", e);
|
throw new IllegalStateException("Fehler beim Laden der XML-Datei", e);
|
||||||
|
|
||||||
|
|
@ -140,12 +154,12 @@ public class Helper {
|
||||||
* @return ein {@link ContentRepository}
|
* @return ein {@link ContentRepository}
|
||||||
*/
|
*/
|
||||||
public static ContentRepository loadTestRepository() {
|
public static ContentRepository loadTestRepository() {
|
||||||
return new ContentRepository(ObjectFactory.createProcessor(), new File("src/test/resources/examples/repository").toURI());
|
return new ContentRepository(TestObjectFactory.createProcessor(), new File("src/test/resources/examples/repository").toURI(), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String serialize(final Document doc) {
|
public static String serialize(final Document doc) {
|
||||||
try ( final StringWriter writer = new StringWriter() ) {
|
try ( final StringWriter writer = new StringWriter() ) {
|
||||||
final Transformer transformer = ObjectFactory.createTransformer(true);
|
final Transformer transformer = TestObjectFactory.createTransformer(true);
|
||||||
transformer.transform(new DOMSource(doc), new StreamResult(writer));
|
transformer.transform(new DOMSource(doc), new StreamResult(writer));
|
||||||
return writer.toString();
|
return writer.toString();
|
||||||
} catch (final IOException | TransformerException e) {
|
} catch (final IOException | TransformerException e) {
|
||||||
|
|
@ -157,4 +171,7 @@ public class Helper {
|
||||||
return serialize((Document) NodeOverNodeInfo.wrap(node.getUnderlyingNode()));
|
return serialize((Document) NodeOverNodeInfo.wrap(node.getUnderlyingNode()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Result<XdmNode, XMLSyntaxError> parseDocument(final Input input) {
|
||||||
|
return new DocumentParseAction(TestObjectFactory.createProcessor()).parseDocument(input);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,8 @@ import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.rules.ExpectedException;
|
import org.junit.rules.ExpectedException;
|
||||||
|
|
||||||
|
import de.kosit.validationtool.impl.xml.RelativeUriResolver;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Testet den Uri-Resolver der relative auflösen soll
|
* Testet den Uri-Resolver der relative auflösen soll
|
||||||
*
|
*
|
||||||
|
|
@ -63,13 +65,13 @@ public class RelativeUriResolverTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNotExisting() throws TransformerException {
|
public void testNotExisting() throws TransformerException {
|
||||||
this.exception.expect(IllegalStateException.class);
|
this.exception.expect(TransformerException.class);
|
||||||
this.resolver.resolve("ubl-0001", BASE.toASCIIString());
|
this.resolver.resolve("ubl-0001", BASE.toASCIIString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOutOfPath() throws TransformerException {
|
public void testOutOfPath() throws TransformerException {
|
||||||
this.exception.expect(IllegalStateException.class);
|
this.exception.expect(TransformerException.class);
|
||||||
this.resolver.resolve("../results/report.xml", BASE.toASCIIString());
|
this.resolver.resolve("../results/report.xml", BASE.toASCIIString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,21 +35,19 @@ import org.w3c.dom.Document;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import de.kosit.validationtool.api.InputFactory;
|
||||||
import de.kosit.validationtool.impl.Helper.Simple;
|
import de.kosit.validationtool.impl.Helper.Simple;
|
||||||
|
import de.kosit.validationtool.impl.model.Result;
|
||||||
|
import de.kosit.validationtool.impl.xml.RelativeUriResolver;
|
||||||
|
import de.kosit.validationtool.model.reportInput.XMLSyntaxError;
|
||||||
|
|
||||||
import net.sf.saxon.s9api.DOMDestination;
|
import net.sf.saxon.s9api.DOMDestination;
|
||||||
import net.sf.saxon.s9api.Processor;
|
import net.sf.saxon.s9api.Processor;
|
||||||
import net.sf.saxon.s9api.SaxonApiException;
|
import net.sf.saxon.s9api.SaxonApiException;
|
||||||
|
import net.sf.saxon.s9api.XdmNode;
|
||||||
import net.sf.saxon.s9api.XsltCompiler;
|
import net.sf.saxon.s9api.XsltCompiler;
|
||||||
import net.sf.saxon.s9api.XsltExecutable;
|
import net.sf.saxon.s9api.XsltExecutable;
|
||||||
import net.sf.saxon.s9api.XsltTransformer;
|
import net.sf.saxon.s9api.XsltTransformer;
|
||||||
import de.kosit.validationtool.api.InputFactory;
|
|
||||||
import de.kosit.validationtool.impl.model.Result;
|
|
||||||
import de.kosit.validationtool.impl.tasks.DocumentParseAction;
|
|
||||||
import de.kosit.validationtool.model.reportInput.XMLSyntaxError;
|
|
||||||
|
|
||||||
|
|
||||||
import net.sf.saxon.s9api.XdmNode;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -62,19 +60,19 @@ public class SaxonSecurityTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEvilStylesheets() throws IOException {
|
public void testEvilStylesheets() throws IOException {
|
||||||
final Processor p = ObjectFactory.createProcessor();
|
final Processor p = TestObjectFactory.createProcessor();
|
||||||
for (int i = 1; i <= 5; i++) {
|
for (int i = 1; i <= 5; i++) {
|
||||||
try {
|
try {
|
||||||
final URL resource = SaxonSecurityTest.class.getResource(String.format("/evil/evil%s.xsl", i));
|
final URL resource = SaxonSecurityTest.class.getResource(String.format("/evil/evil%s.xsl", i));
|
||||||
final XsltCompiler compiler = p.newXsltCompiler();
|
final XsltCompiler compiler = p.newXsltCompiler();
|
||||||
final RelativeUriResolver resolver = new RelativeUriResolver(Simple.REPOSITORY);
|
final RelativeUriResolver resolver = new RelativeUriResolver(Simple.REPOSITORY_URI);
|
||||||
compiler.setURIResolver(resolver);
|
compiler.setURIResolver(resolver);
|
||||||
final XsltExecutable exetuable = compiler.compile(new StreamSource(resource.openStream()));
|
final XsltExecutable exetuable = compiler.compile(new StreamSource(resource.openStream()));
|
||||||
final XsltTransformer transformer = exetuable.load();
|
final XsltTransformer transformer = exetuable.load();
|
||||||
final Document document = ObjectFactory.createDocumentBuilder(false).newDocument();
|
final Document document = TestObjectFactory.createDocumentBuilder(false).newDocument();
|
||||||
document.createElement("root");
|
document.createElement("root");
|
||||||
final Document result = ObjectFactory.createDocumentBuilder(false).newDocument();
|
final Document result = TestObjectFactory.createDocumentBuilder(false).newDocument();
|
||||||
transformer.getUnderlyingController().setUnparsedTextURIResolver(resolver);
|
// transformer.getUnderlyingController().setUnparsedTextURIResolver(resolver);
|
||||||
transformer.setURIResolver(resolver);
|
transformer.setURIResolver(resolver);
|
||||||
transformer.setSource(new DOMSource(document));
|
transformer.setSource(new DOMSource(document));
|
||||||
transformer.setDestination(new DOMDestination(result));
|
transformer.setDestination(new DOMDestination(result));
|
||||||
|
|
@ -94,7 +92,7 @@ public class SaxonSecurityTest {
|
||||||
@Test
|
@Test
|
||||||
public void testXxe() {
|
public void testXxe() {
|
||||||
final URL resource = SaxonSecurityTest.class.getResource("/evil/xxe.xml");
|
final URL resource = SaxonSecurityTest.class.getResource("/evil/xxe.xml");
|
||||||
final Result<XdmNode, XMLSyntaxError> result = DocumentParseAction.parseDocument(InputFactory.read(resource));
|
final Result<XdmNode, XMLSyntaxError> result = Helper.parseDocument(InputFactory.read(resource));
|
||||||
assertThat(result.isValid()).isFalse();
|
assertThat(result.isValid()).isFalse();
|
||||||
assertThat(result.getObject()).isNull();
|
assertThat(result.getObject()).isNull();
|
||||||
assertThat(result.getErrors().stream().map(XMLSyntaxError::getMessage).collect(Collectors.joining()))
|
assertThat(result.getErrors().stream().map(XMLSyntaxError::getMessage).collect(Collectors.joining()))
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ import java.net.URI;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
|
|
@ -38,7 +39,6 @@ import lombok.Data;
|
||||||
import de.kosit.validationtool.api.Configuration;
|
import de.kosit.validationtool.api.Configuration;
|
||||||
import de.kosit.validationtool.impl.Helper.Simple;
|
import de.kosit.validationtool.impl.Helper.Simple;
|
||||||
import de.kosit.validationtool.impl.model.Result;
|
import de.kosit.validationtool.impl.model.Result;
|
||||||
import de.kosit.validationtool.impl.tasks.DocumentParseAction;
|
|
||||||
import de.kosit.validationtool.model.scenarios.ScenarioType;
|
import de.kosit.validationtool.model.scenarios.ScenarioType;
|
||||||
|
|
||||||
import net.sf.saxon.s9api.Processor;
|
import net.sf.saxon.s9api.Processor;
|
||||||
|
|
@ -70,10 +70,8 @@ public class ScenarioRepositoryTest {
|
||||||
|
|
||||||
private ContentRepository contentRepository;
|
private ContentRepository contentRepository;
|
||||||
|
|
||||||
@Override
|
private Map<String, Object> additionalParameters;
|
||||||
public void build() {
|
|
||||||
// nothing
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Rule
|
@Rule
|
||||||
|
|
@ -137,11 +135,10 @@ public class ScenarioRepositoryTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static XdmNode load(final URI uri) throws IOException {
|
private static XdmNode load(final URI uri) throws IOException {
|
||||||
final DocumentParseAction p = new DocumentParseAction();
|
return Helper.parseDocument(read(uri.toURL())).getObject();
|
||||||
return DocumentParseAction.parseDocument(read(uri.toURL())).getObject();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static XPathExecutable createXpath(final String expression) {
|
private static XPathExecutable createXpath(final String expression) {
|
||||||
return new ContentRepository(ObjectFactory.createProcessor(), null).createXPath(expression, new HashMap<>());
|
return new ContentRepository(TestObjectFactory.createProcessor(), null, null).createXPath(expression, new HashMap<>());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ public class SimpleScenarioCheckTest {
|
||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() {
|
||||||
final CheckConfiguration d = new CheckConfiguration(Simple.SCENARIOS);
|
final CheckConfiguration d = new CheckConfiguration(Simple.SCENARIOS);
|
||||||
d.setScenarioRepository(Simple.REPOSITORY);
|
d.setScenarioRepository(Simple.REPOSITORY_URI);
|
||||||
this.implementation = new DefaultCheck(d);
|
this.implementation = new DefaultCheck(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
package de.kosit.validationtool.impl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Andreas Penski
|
||||||
|
*/
|
||||||
|
public class TestObjectFactory extends ObjectFactory {
|
||||||
|
}
|
||||||
|
|
@ -56,7 +56,7 @@ public class VersioningTest {
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() {
|
||||||
this.repository = new ContentRepository(ObjectFactory.createProcessor(), Simple.REPOSITORY);
|
this.repository = Simple.createContentRepository();
|
||||||
this.service = new ConversionService();
|
this.service = new ConversionService();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ import org.junit.Test;
|
||||||
|
|
||||||
import de.kosit.validationtool.api.AcceptRecommendation;
|
import de.kosit.validationtool.api.AcceptRecommendation;
|
||||||
import de.kosit.validationtool.impl.ContentRepository;
|
import de.kosit.validationtool.impl.ContentRepository;
|
||||||
import de.kosit.validationtool.impl.ObjectFactory;
|
import de.kosit.validationtool.impl.TestObjectFactory;
|
||||||
import de.kosit.validationtool.impl.tasks.CheckAction.Bag;
|
import de.kosit.validationtool.impl.tasks.CheckAction.Bag;
|
||||||
|
|
||||||
import net.sf.saxon.s9api.XPathExecutable;
|
import net.sf.saxon.s9api.XPathExecutable;
|
||||||
|
|
@ -22,6 +22,7 @@ import net.sf.saxon.s9api.XPathExecutable;
|
||||||
*/
|
*/
|
||||||
public class ComputeAcceptanceActionTest {
|
public class ComputeAcceptanceActionTest {
|
||||||
|
|
||||||
|
private static final String DOESNOT_EXIST = "count(//doesnotExist) = 0";
|
||||||
private final ComputeAcceptanceAction action = new ComputeAcceptanceAction();
|
private final ComputeAcceptanceAction action = new ComputeAcceptanceAction();
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -49,7 +50,7 @@ public class ComputeAcceptanceActionTest {
|
||||||
@Test
|
@Test
|
||||||
public void testValidAcceptMatch() {
|
public void testValidAcceptMatch() {
|
||||||
final Bag bag = createBag(true, true);
|
final Bag bag = createBag(true, true);
|
||||||
bag.getScenarioSelectionResult().getObject().setAcceptExecutable(createXpath("count(//doesnotExist) = 0"));
|
bag.getScenarioSelectionResult().getObject().setAcceptExecutable(createXpath(DOESNOT_EXIST));
|
||||||
this.action.check(bag);
|
this.action.check(bag);
|
||||||
assertThat(bag.getAcceptStatus()).isEqualTo(AcceptRecommendation.ACCEPTABLE);
|
assertThat(bag.getAcceptStatus()).isEqualTo(AcceptRecommendation.ACCEPTABLE);
|
||||||
}
|
}
|
||||||
|
|
@ -65,7 +66,7 @@ public class ComputeAcceptanceActionTest {
|
||||||
@Test
|
@Test
|
||||||
public void testAcceptMatchOverridesSchematronErrors() {
|
public void testAcceptMatchOverridesSchematronErrors() {
|
||||||
final Bag bag = createBag(true, false);
|
final Bag bag = createBag(true, false);
|
||||||
bag.getScenarioSelectionResult().getObject().setAcceptExecutable(createXpath("count(//doesnotExist) = 0"));
|
bag.getScenarioSelectionResult().getObject().setAcceptExecutable(createXpath(DOESNOT_EXIST));
|
||||||
this.action.check(bag);
|
this.action.check(bag);
|
||||||
assertThat(bag.getAcceptStatus()).isEqualTo(AcceptRecommendation.ACCEPTABLE);
|
assertThat(bag.getAcceptStatus()).isEqualTo(AcceptRecommendation.ACCEPTABLE);
|
||||||
}
|
}
|
||||||
|
|
@ -73,7 +74,7 @@ public class ComputeAcceptanceActionTest {
|
||||||
@Test
|
@Test
|
||||||
public void testValidAcceptMatchOnSchemaFailed() {
|
public void testValidAcceptMatchOnSchemaFailed() {
|
||||||
final Bag bag = createBag(false, true);
|
final Bag bag = createBag(false, true);
|
||||||
bag.getScenarioSelectionResult().getObject().setAcceptExecutable(createXpath("count(//doesnotExist) = 0"));
|
bag.getScenarioSelectionResult().getObject().setAcceptExecutable(createXpath(DOESNOT_EXIST));
|
||||||
this.action.check(bag);
|
this.action.check(bag);
|
||||||
assertThat(bag.getAcceptStatus()).isEqualTo(AcceptRecommendation.REJECT);
|
assertThat(bag.getAcceptStatus()).isEqualTo(AcceptRecommendation.REJECT);
|
||||||
}
|
}
|
||||||
|
|
@ -104,6 +105,6 @@ public class ComputeAcceptanceActionTest {
|
||||||
|
|
||||||
|
|
||||||
private static XPathExecutable createXpath(final String expression) {
|
private static XPathExecutable createXpath(final String expression) {
|
||||||
return new ContentRepository(ObjectFactory.createProcessor(), null).createXPath(expression, new HashMap<>());
|
return new ContentRepository(TestObjectFactory.createProcessor(), null, null).createXPath(expression, new HashMap<>());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,12 +43,13 @@ import org.xml.sax.SAXException;
|
||||||
|
|
||||||
import de.kosit.validationtool.api.Input;
|
import de.kosit.validationtool.api.Input;
|
||||||
import de.kosit.validationtool.api.InputFactory;
|
import de.kosit.validationtool.api.InputFactory;
|
||||||
import de.kosit.validationtool.impl.ContentRepository;
|
import de.kosit.validationtool.impl.Helper;
|
||||||
import de.kosit.validationtool.impl.Helper.Simple;
|
import de.kosit.validationtool.impl.Helper.Simple;
|
||||||
import de.kosit.validationtool.impl.ObjectFactory;
|
|
||||||
import de.kosit.validationtool.impl.Scenario;
|
import de.kosit.validationtool.impl.Scenario;
|
||||||
|
import de.kosit.validationtool.impl.TestObjectFactory;
|
||||||
import de.kosit.validationtool.impl.input.SourceInput;
|
import de.kosit.validationtool.impl.input.SourceInput;
|
||||||
import de.kosit.validationtool.impl.tasks.CheckAction.Bag;
|
import de.kosit.validationtool.impl.tasks.CheckAction.Bag;
|
||||||
|
import de.kosit.validationtool.impl.xml.StrictRelativeResolvingStrategy;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests die {@link SchemaValidationAction}.
|
* Tests die {@link SchemaValidationAction}.
|
||||||
|
|
@ -63,7 +64,7 @@ public class SchemaValidatorActionTest {
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() {
|
||||||
this.service = new SchemaValidationAction();
|
this.service = new SchemaValidationAction(new StrictRelativeResolvingStrategy(), TestObjectFactory.createProcessor());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -89,7 +90,7 @@ public class SchemaValidatorActionTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSchemaReferences() {
|
public void testSchemaReferences() {
|
||||||
final Schema reportInputSchema = new ContentRepository(ObjectFactory.createProcessor(), Simple.REPOSITORY).getReportInputSchema();
|
final Schema reportInputSchema = Simple.createContentRepository().getReportInputSchema();
|
||||||
assertThat(reportInputSchema).isNotNull();
|
assertThat(reportInputSchema).isNotNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -98,7 +99,7 @@ public class SchemaValidatorActionTest {
|
||||||
try ( final InputStream inputStream = Simple.SIMPLE_VALID.toURL().openStream() ) {
|
try ( final InputStream inputStream = Simple.SIMPLE_VALID.toURL().openStream() ) {
|
||||||
final Bag bag = createBag(InputFactory.read(new StreamSource(inputStream)));
|
final Bag bag = createBag(InputFactory.read(new StreamSource(inputStream)));
|
||||||
// don't read the real inputstream here!
|
// don't read the real inputstream here!
|
||||||
bag.setParserResult(DocumentParseAction.parseDocument(InputFactory.read(Simple.SIMPLE_VALID.toURL())));
|
bag.setParserResult(Helper.parseDocument(InputFactory.read(Simple.SIMPLE_VALID.toURL())));
|
||||||
this.service.check(bag);
|
this.service.check(bag);
|
||||||
assertThat(bag.getSchemaValidationResult()).isNotNull();
|
assertThat(bag.getSchemaValidationResult()).isNotNull();
|
||||||
assertThat(bag.getSchemaValidationResult().isValid()).isTrue();
|
assertThat(bag.getSchemaValidationResult().isValid()).isTrue();
|
||||||
|
|
@ -114,7 +115,7 @@ public class SchemaValidatorActionTest {
|
||||||
this.service.setInMemoryLimit(5L);
|
this.service.setInMemoryLimit(5L);
|
||||||
input.setLength(6L);
|
input.setLength(6L);
|
||||||
|
|
||||||
bag.setParserResult(DocumentParseAction.parseDocument(InputFactory.read(Simple.SIMPLE_VALID.toURL())));
|
bag.setParserResult(Helper.parseDocument(InputFactory.read(Simple.SIMPLE_VALID.toURL())));
|
||||||
this.service.check(bag);
|
this.service.check(bag);
|
||||||
assertThat(bag.getSchemaValidationResult()).isNotNull();
|
assertThat(bag.getSchemaValidationResult()).isNotNull();
|
||||||
assertThat(bag.getSchemaValidationResult().isValid()).isTrue();
|
assertThat(bag.getSchemaValidationResult().isValid()).isTrue();
|
||||||
|
|
@ -127,7 +128,7 @@ public class SchemaValidatorActionTest {
|
||||||
final Reader reader = new InputStreamReader(inputStream) ) {
|
final Reader reader = new InputStreamReader(inputStream) ) {
|
||||||
final SourceInput input = (SourceInput) InputFactory.read(new StreamSource(reader));
|
final SourceInput input = (SourceInput) InputFactory.read(new StreamSource(reader));
|
||||||
final Bag bag = createBag(input);
|
final Bag bag = createBag(input);
|
||||||
bag.setParserResult(DocumentParseAction.parseDocument(InputFactory.read(Simple.SIMPLE_VALID.toURL())));
|
bag.setParserResult(Helper.parseDocument(InputFactory.read(Simple.SIMPLE_VALID.toURL())));
|
||||||
this.service.check(bag);
|
this.service.check(bag);
|
||||||
this.service.check(bag);
|
this.service.check(bag);
|
||||||
assertThat(bag.getSchemaValidationResult()).isNotNull();
|
assertThat(bag.getSchemaValidationResult()).isNotNull();
|
||||||
|
|
@ -143,7 +144,7 @@ public class SchemaValidatorActionTest {
|
||||||
final Bag bag = createBag(input);
|
final Bag bag = createBag(input);
|
||||||
// set limit and length for serialization to 5 bytes
|
// set limit and length for serialization to 5 bytes
|
||||||
this.service.setInMemoryLimit(5L);
|
this.service.setInMemoryLimit(5L);
|
||||||
bag.setParserResult(DocumentParseAction.parseDocument(InputFactory.read(Simple.SIMPLE_VALID.toURL())));
|
bag.setParserResult(Helper.parseDocument(InputFactory.read(Simple.SIMPLE_VALID.toURL())));
|
||||||
this.service.check(bag);
|
this.service.check(bag);
|
||||||
this.service.check(bag);
|
this.service.check(bag);
|
||||||
assertThat(bag.getSchemaValidationResult()).isNotNull();
|
assertThat(bag.getSchemaValidationResult()).isNotNull();
|
||||||
|
|
|
||||||
|
|
@ -13,12 +13,11 @@ import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import de.kosit.validationtool.api.InputFactory;
|
import de.kosit.validationtool.api.InputFactory;
|
||||||
import de.kosit.validationtool.impl.ContentRepository;
|
|
||||||
import de.kosit.validationtool.impl.ConversionService;
|
import de.kosit.validationtool.impl.ConversionService;
|
||||||
import de.kosit.validationtool.impl.Helper.Simple;
|
import de.kosit.validationtool.impl.Helper.Simple;
|
||||||
import de.kosit.validationtool.impl.ObjectFactory;
|
|
||||||
import de.kosit.validationtool.impl.Scenario;
|
import de.kosit.validationtool.impl.Scenario;
|
||||||
import de.kosit.validationtool.impl.Scenario.Transformation;
|
import de.kosit.validationtool.impl.Scenario.Transformation;
|
||||||
|
import de.kosit.validationtool.impl.xml.RelativeUriResolver;
|
||||||
import de.kosit.validationtool.model.scenarios.ResourceType;
|
import de.kosit.validationtool.model.scenarios.ResourceType;
|
||||||
|
|
||||||
import net.sf.saxon.s9api.SaxonApiException;
|
import net.sf.saxon.s9api.SaxonApiException;
|
||||||
|
|
@ -36,8 +35,7 @@ public class SchematronValidationActionTest {
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() {
|
||||||
final ContentRepository repository = new ContentRepository(ObjectFactory.createProcessor(), Simple.REPOSITORY);
|
this.action = new SchematronValidationAction(new RelativeUriResolver(Simple.REPOSITORY_URI), new ConversionService());
|
||||||
this.action = new SchematronValidationAction(repository, new ConversionService());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,9 @@ import de.kosit.validationtool.api.Input;
|
||||||
import de.kosit.validationtool.api.InputFactory;
|
import de.kosit.validationtool.api.InputFactory;
|
||||||
import de.kosit.validationtool.impl.ContentRepository;
|
import de.kosit.validationtool.impl.ContentRepository;
|
||||||
import de.kosit.validationtool.impl.Helper;
|
import de.kosit.validationtool.impl.Helper;
|
||||||
import de.kosit.validationtool.impl.ObjectFactory;
|
import de.kosit.validationtool.impl.ResolvingMode;
|
||||||
import de.kosit.validationtool.impl.Scenario;
|
import de.kosit.validationtool.impl.Scenario;
|
||||||
|
import de.kosit.validationtool.impl.TestObjectFactory;
|
||||||
import de.kosit.validationtool.impl.model.Result;
|
import de.kosit.validationtool.impl.model.Result;
|
||||||
import de.kosit.validationtool.impl.tasks.CheckAction.Bag;
|
import de.kosit.validationtool.impl.tasks.CheckAction.Bag;
|
||||||
import de.kosit.validationtool.model.reportInput.CreateReportInput;
|
import de.kosit.validationtool.model.reportInput.CreateReportInput;
|
||||||
|
|
@ -48,7 +49,7 @@ public class TestBagBuilder {
|
||||||
public static Bag createBag(final Input input, final boolean parse, final CreateReportInput reportInput) {
|
public static Bag createBag(final Input input, final boolean parse, final CreateReportInput reportInput) {
|
||||||
final Bag bag = new Bag(input, reportInput);
|
final Bag bag = new Bag(input, reportInput);
|
||||||
if (parse) {
|
if (parse) {
|
||||||
bag.setParserResult(DocumentParseAction.parseDocument(bag.getInput()));
|
bag.setParserResult(Helper.parseDocument(bag.getInput()));
|
||||||
}
|
}
|
||||||
bag.setScenarioSelectionResult(new Result<>(createScenario(Helper.Simple.getSchemaLocation())));
|
bag.setScenarioSelectionResult(new Result<>(createScenario(Helper.Simple.getSchemaLocation())));
|
||||||
return bag;
|
return bag;
|
||||||
|
|
@ -73,11 +74,13 @@ public class TestBagBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Schema createSchema(final URL toURL) {
|
private static Schema createSchema(final URL toURL) {
|
||||||
return new ContentRepository(ObjectFactory.createProcessor(), null).createSchema(toURL);
|
final ContentRepository contentRepository = new ContentRepository(TestObjectFactory.createProcessor(), null, null);
|
||||||
|
contentRepository.setSchemaFactory(ResolvingMode.STRICT_RELATIVE.getStrategy().createSchemaFactory());
|
||||||
|
return contentRepository.createSchema(toURL);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static XdmNode createReport() {
|
private static XdmNode createReport() {
|
||||||
return DocumentParseAction.parseDocument(InputFactory.read("<some>xml</some>".getBytes(), "someXml")).getObject();
|
return Helper.parseDocument(InputFactory.read("<some>xml</some>".getBytes(), "someXml")).getObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
static Bag createBag(final boolean schemaValid, final boolean schematronValid) {
|
static Bag createBag(final boolean schemaValid, final boolean schematronValid) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue