Refactor: don't reuse JAXB objects for internal configuration; create a Configuration interface.

This commit is contained in:
Andreas Penski (init) 2020-04-21 08:34:56 +02:00
parent c8b3c1977c
commit 7a86f049ac
30 changed files with 871 additions and 517 deletions

View file

@ -20,24 +20,31 @@
package de.kosit.validationtool.api;
import java.net.URI;
import java.util.List;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import de.kosit.validationtool.impl.RelativeUriResolver;
import de.kosit.validationtool.config.LoadConfiguration;
import de.kosit.validationtool.impl.ContentRepository;
import de.kosit.validationtool.impl.Scenario;
import net.sf.saxon.s9api.Processor;
/**
* Zentrale Konfigration einer Prüf-Instanz.
*
* @author Andreas Penski
* @deprecated since 2.0 use {@link Configuration} instead
*/
@Getter
@Setter
@Slf4j
@RequiredArgsConstructor
public class CheckConfiguration {
@Deprecated
public class CheckConfiguration implements Configuration {
/**
* URL, die auf die scenerio.xml Datei zeigt.
@ -49,22 +56,52 @@ public class CheckConfiguration {
*/
private URI scenarioRepository;
private LoadConfiguration delegate;
/**
* Liefert das Repository mit den Artefakten der einzelnen Szenarien.
*
* @return uri die durch entsprechende resolver aufgelöst werden kann
*/
public URI getScenarioRepository() {
if (this.scenarioRepository == null) {
this.scenarioRepository = createDefaultRepository();
private LoadConfiguration getDelegate() {
if (this.delegate == null) {
this.delegate = Configuration.load(this.scenarioDefinition, this.scenarioRepository);
}
return this.scenarioRepository;
return this.delegate;
}
private URI createDefaultRepository() {
log.info("Creating default scenario repository (alongside scenario definition)");
return RelativeUriResolver.resolve(URI.create("."), this.scenarioDefinition);
@Override
public List<Scenario> getScenarios() {
return getDelegate().getScenarios();
}
@Override
public Scenario getFallbackScenario() {
return getDelegate().getFallbackScenario();
}
@Override
public void build() {
getDelegate().build();
}
@Override
public String getDate() {
return getDelegate().getDate();
}
@Override
public String getName() {
return getDelegate().getName();
}
@Override
public String getAuthor() {
return getDelegate().getAuthor();
}
@Override
public Processor getProcessor() {
return getDelegate().getProcessor();
}
@Override
public ContentRepository getContentRepository() {
return getDelegate().getContentRepository();
}
}

View file

@ -0,0 +1,59 @@
package de.kosit.validationtool.api;
import java.net.URI;
import java.util.List;
import de.kosit.validationtool.config.ConfigurationBuilder;
import de.kosit.validationtool.config.LoadConfiguration;
import de.kosit.validationtool.impl.ContentRepository;
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 classes. There are two implementations supported out of the box:
*
* <ol>
* <li>{@link LoadConfiguration} 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
* {@link Check}</li>
* </ol>
*
* Both methods can be used via convinience methods. See below.
*
* @author Andreas Penski
*/
public interface Configuration {
List<Scenario> getScenarios();
static LoadConfiguration load(final URI scenarioDefinition) {
return load(scenarioDefinition, null);
}
static LoadConfiguration load(final URI scenarioDefinition, final URI repository) {
final LoadConfiguration config = new LoadConfiguration(scenarioDefinition, repository);
config.build();
return config;
}
static ConfigurationBuilder create() {
return new ConfigurationBuilder();
}
Scenario getFallbackScenario();
void build();
String getAuthor();
String getName();
String getDate();
Processor getProcessor();
ContentRepository getContentRepository();
}

View file

@ -27,11 +27,11 @@ 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;
import de.kosit.validationtool.model.scenarios.Scenarios;
/**
* HTTP-Daemon für die Bereitstellung der Prüf-Funktionalität via http.
@ -98,10 +98,10 @@ class Daemon {
@Slf4j
static class HealthHandler implements HttpHandler {
private final Scenarios scenarios;
private final Configuration scenarios;
HealthHandler(final Scenarios scenarios) {
this.scenarios = scenarios;
HealthHandler(final Configuration config) {
this.scenarios = config;
}
@Override
@ -188,7 +188,7 @@ class Daemon {
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(check.getRepository().getScenarios()));
server.createContext("/health", new HealthHandler(config));
server.setExecutor(Executors.newFixedThreadPool(this.threadCount));
server.start();
log.info("Server unter Port {} ist erfolgreich gestartet", this.port);

View file

@ -1,8 +1,6 @@
package de.kosit.validationtool.cmd;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
@ -10,7 +8,8 @@ import org.w3c.dom.Node;
import lombok.extern.slf4j.Slf4j;
import de.kosit.validationtool.model.scenarios.Scenarios;
import de.kosit.validationtool.api.Configuration;
import de.kosit.validationtool.impl.ObjectFactory;
/**
* Klasse zur Erzeugung Health Xml , die optiamle Status.
@ -26,15 +25,15 @@ class Health {
private final long totalMemory;
private final Scenarios scenarios;
private final Configuration config;
Health(Scenarios scenarios) {
Health(final Configuration config) {
Runtime runtime = Runtime.getRuntime();
freeMemory = runtime.freeMemory();
maxMemory = runtime.maxMemory();
totalMemory = runtime.totalMemory();
this.scenarios = scenarios;
final Runtime runtime = Runtime.getRuntime();
this.freeMemory = runtime.freeMemory();
this.maxMemory = runtime.maxMemory();
this.totalMemory = runtime.totalMemory();
this.config = config;
}
/**
@ -42,20 +41,13 @@ class Health {
*
*/
Document writeHealthXml() {
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder;
Document doc = null;
try {
dBuilder = dbFactory.newDocumentBuilder();
doc = dBuilder.newDocument();
Element rootElement = doc.createElementNS("https://localhost:8080/Health", "Health");
doc.appendChild(rootElement);
rootElement.appendChild(getMemory(doc, freeMemory, maxMemory, totalMemory));
rootElement.appendChild(getState(doc));
rootElement.appendChild(getScenario(doc, scenarios));
} catch (ParserConfigurationException e) {
log.error("Fehler beim Schreiben der Status-Informationen", e);
}
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;
}
@ -65,10 +57,10 @@ class Health {
* @param doc Vom Typ Dokument.
*
*/
private Node getState(Document doc) {
Element state = doc.createElement("state");
private static Node getState(final Document doc) {
final Element state = doc.createElement("state");
state.setAttribute("indicator", "OK");
Element stateNode = doc.createElement("message");
final Element stateNode = doc.createElement("message");
stateNode.appendChild(doc.createTextNode("System is up and running normally"));
state.appendChild(stateNode);
return state;
@ -78,13 +70,13 @@ class Health {
* Methode, die schreibt das Scnarios Information Node im Xml File
*
* @param doc Vom Typ Dokument .
* @param scenarios Vom Typ {@link Scenarios} das verwendete scenario.
* @param config Vom Typ {@link Configuration} das verwendete scenario.
*
*/
private Node getScenario(Document doc, Scenarios scenarios) {
Element scenario = doc.createElement("scenario");
Element scenarioNameNode = doc.createElement("name");
scenarioNameNode.appendChild(doc.createTextNode(scenarios.getName()));
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;
}
@ -98,18 +90,18 @@ class Health {
* @param totalMemory Vom Typ long , der Gesamte speicher.
*
*/
private static Node getMemory(Document doc, long freeMemory, long maxMemory, long totalMemory) {
Element memory = doc.createElement("memoryState");
String freeM = Long.toString(freeMemory);
Element freeMNode = doc.createElement("freeMemory");
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);
String maxM = Long.toString(maxMemory);
Element maxMNode = doc.createElement("maxMemory");
final String maxM = Long.toString(maxMemory);
final Element maxMNode = doc.createElement("maxMemory");
maxMNode.appendChild(doc.createTextNode(maxM));
memory.appendChild(maxMNode);
String totalM = Long.toString(totalMemory);
Element totalMNode = doc.createElement("totalMemory");
final String totalM = Long.toString(totalMemory);
final Element totalMNode = doc.createElement("totalMemory");
totalMNode.appendChild(doc.createTextNode(totalM));
memory.appendChild(totalMNode);
return memory;

View file

@ -0,0 +1,92 @@
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();
}
}

View file

@ -0,0 +1,10 @@
package de.kosit.validationtool.config;
/**
* @author Andreas Penski
*/
public class ConfigurationBuilder {
private ScenarioBuilder scenarioBuilder;
}

View file

@ -0,0 +1,178 @@
package de.kosit.validationtool.config;
import static org.apache.commons.lang3.StringUtils.startsWith;
import java.net.MalformedURLException;
import java.net.URI;
import java.util.List;
import java.util.stream.Collectors;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import de.kosit.validationtool.api.Check;
import de.kosit.validationtool.api.InputFactory;
import de.kosit.validationtool.impl.CollectingErrorEventHandler;
import de.kosit.validationtool.impl.ContentRepository;
import de.kosit.validationtool.impl.ConversionService;
import de.kosit.validationtool.impl.RelativeUriResolver;
import de.kosit.validationtool.impl.Scenario;
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.scenarios.CreateReportType;
import de.kosit.validationtool.model.scenarios.ScenarioType;
import de.kosit.validationtool.model.scenarios.Scenarios;
import net.sf.saxon.s9api.QName;
import net.sf.saxon.s9api.XdmNode;
import net.sf.saxon.s9api.XdmNodeKind;
/**
* Configuration class that loads neccessary {@link Check} configuration from an existing scenario.xml specification.
* This is the recommended option when an official configuration exists as is the case with 'xrechnung'.
*
* @author Andreas Penski
*/
@AllArgsConstructor
@Slf4j
public class LoadConfiguration extends BaseConfiguration {
private static final String SUPPORTED_MAJOR_VERSION = "1";
private static final String SUPPORTED_MAJOR_VERSION_SCHEMA = "http://www.xoev.de/de/validator/framework/1/scenarios";
/**
* URL, die auf die scenerio.xml Datei zeigt.
*/
@Getter(AccessLevel.PACKAGE)
private final URI scenarioDefinition;
/**
* Root-Ordner mit den von den einzelnen Szenarien benötigten Dateien
*/
private final URI scenarioRepository;
URI getScenarioRepository() {
if (this.scenarioRepository == null) {
log.info("Creating default scenario repository (alongside scenario definition)");
return RelativeUriResolver.resolve(URI.create("."), this.scenarioDefinition);
}
return this.scenarioRepository;
}
private static void checkVersion(final URI scenarioDefinition) {
try {
final Result<XdmNode, XMLSyntaxError> result = DocumentParseAction.parseDocument(InputFactory.read(scenarioDefinition.toURL()));
if (result.isValid() && !isSupportedDocument(result.getObject())) {
throw new IllegalStateException(String.format(
"Specified scenario configuration %s is not supported.%nThis version only supports definitions of '%s'",
scenarioDefinition, SUPPORTED_MAJOR_VERSION_SCHEMA));
}
} catch (final MalformedURLException e) {
throw new IllegalStateException("Error reading definition file");
}
}
private static XdmNode findRoot(final XdmNode doc) {
for (final XdmNode node : doc.children()) {
if (node.getNodeKind() == XdmNodeKind.ELEMENT) {
return node;
}
}
throw new IllegalArgumentException("Kein root element gefunden");
}
private static boolean isSupportedDocument(final XdmNode doc) {
final XdmNode root = findRoot(doc);
final String frameworkVersion = root.getAttributeValue(new QName("frameworkVersion"));
return startsWith(frameworkVersion, SUPPORTED_MAJOR_VERSION)
&& root.getNodeName().getNamespaceURI().equals(SUPPORTED_MAJOR_VERSION_SCHEMA);
}
private static Scenario createFallback(final Scenarios scenarios, final ContentRepository repository) {
final ScenarioType t = new ScenarioType();
t.setName("Fallback-Scenario");
t.setMatch("count(/)<0");
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
protected RuntimeArtefacts buildArtefacts() {
final ContentRepository contentRepository = buildContentRepository();
final Scenarios def = loadScenarios();
final List<Scenario> scenarios = initializeScenarios(def, contentRepository);
final Scenario fallbackScenario = createFallback(def, contentRepository);
final RuntimeArtefacts runtimeArtefacts = new RuntimeArtefacts(scenarios, fallbackScenario);
runtimeArtefacts.setAuthor(def.getAuthor());
runtimeArtefacts.setDate(def.getDate().toString());
runtimeArtefacts.setName(def.getName());
return runtimeArtefacts;
}
private static List<Scenario> initializeScenarios(final Scenarios def, final ContentRepository contentRepository) {
return def.getScenario().stream().map(s -> initialize(s, contentRepository)).collect(Collectors.toList());
}
private ContentRepository buildContentRepository() {
return new ContentRepository(getProcessor(), getScenarioRepository());
}
@Override
public ContentRepository getContentRepository() {
return buildContentRepository();
}
private Scenarios loadScenarios() {
final ConversionService conversionService = new ConversionService();
checkVersion(this.scenarioDefinition);
log.info("Loading scenarios from {}", this.scenarioDefinition);
final CollectingErrorEventHandler handler = new CollectingErrorEventHandler();
final Scenarios scenarios = conversionService.readXml(this.scenarioDefinition, Scenarios.class,
getContentRepository().getScenarioSchema(), handler);
if (!handler.hasErrors()) {
log.info("Loading scenario content from {}", this.scenarioRepository);
} else {
throw new IllegalStateException(
String.format("Can not load scenarios from %s due to %s", getScenarioDefinition(), handler.getErrorDescription()));
}
return scenarios;
}
private static Scenario initialize(final ScenarioType def, final ContentRepository repository) {
final Scenario s = new Scenario(def);
s.setSchema(repository.createSchema(def));
s.setReportTransformation(repository.createReportTransformation(def));
s.setMatchExecutable(repository.createMatchExecutable(def));
if (def.getAcceptMatch() != null) {
s.setAcceptExecutable(repository.createAccepptExecutable(def));
}
return s;
}
@Override
public String getAuthor() {
return null;
}
@Override
public String getName() {
return null;
}
@Override
public String getDate() {
return null;
}
}

View file

@ -0,0 +1,72 @@
package de.kosit.validationtool.config;
import java.net.URL;
import java.util.Collections;
import java.util.Map;
import javax.xml.validation.Schema;
import org.w3c.dom.ls.LSResourceResolver;
import de.kosit.validationtool.impl.ContentRepository;
import de.kosit.validationtool.impl.ObjectFactory;
import de.kosit.validationtool.model.scenarios.ScenarioType;
import net.sf.saxon.s9api.XsltExecutable;
/**
* @author Andreas Penski
*/
public class ScenarioBuilder {
private final ScenarioType scenario;
private final ContentRepository contentRepository = new ContentRepository(ObjectFactory.createProcessor(), null);
ScenarioBuilder(final String name) {
this.scenario = new ScenarioType();
this.scenario.setName(name);
}
public ScenarioBuilder matches(final String xpath) {
return matches(xpath, Collections.emptyMap());
}
private ScenarioBuilder matches(final String xpath, final Map<String, String> namespaces) {
// final XPathExecutable matchExecutable = this.contentRepository.createXPath(xpath, namespaces);
// this.scenario.setMatchExecutable(matchExecutable);
// this.scenario.setMatch(xpath);
// 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;
}
public ScenarioBuilder schemaValidation(final Schema schema) {
return this;
}
public ScenarioBuilder schemaValidation(final URL url) {
return schemalidation(url, null);
}
private ScenarioBuilder schemalidation(final URL url, final LSResourceResolver resolver) {
return this;
}
public ScenarioBuilder addSchematronValidation(final XsltExecutable executable) {
return this;
}
public ScenarioBuilder withReportGenerator(final XsltExecutable executable) {
return this;
}
}

View file

@ -24,9 +24,12 @@ import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.xml.transform.Source;
import javax.xml.transform.URIResolver;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
@ -39,6 +42,11 @@ import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import de.kosit.validationtool.impl.Scenario.Transformation;
import de.kosit.validationtool.model.scenarios.NamespaceType;
import de.kosit.validationtool.model.scenarios.ResourceType;
import de.kosit.validationtool.model.scenarios.ScenarioType;
import net.sf.saxon.s9api.Processor;
import net.sf.saxon.s9api.SaxonApiException;
import net.sf.saxon.s9api.XPathCompiler;
@ -55,14 +63,16 @@ import net.sf.saxon.s9api.XsltExecutable;
@Slf4j
public class ContentRepository {
private Schema reportInputSchema;
@Getter
private final Processor processor;
private final URI repository;
private Schema reportInputSchema;
private final ResolvingMode mode = ResolvingMode.STRICT_RELATIVE;
private static Source resolve(final URL resource) {
private Source resolve(final URL resource) {
try {
return new StreamSource(resource.openStream(), resource.toURI().getRawPath());
} catch (final IOException | URISyntaxException e) {
@ -70,7 +80,7 @@ public class ContentRepository {
}
}
private static Schema createSchema(final Source[] schemaSources, final LSResourceResolver resourceResolver) {
private Schema createSchema(final Source[] schemaSources, final LSResourceResolver resourceResolver) {
try {
final SchemaFactory sf = ObjectFactory.createSchemaFactory();
sf.setResourceResolver(resourceResolver);
@ -80,7 +90,7 @@ public class ContentRepository {
}
}
private static Schema createSchema(final Source[] schemaSources) {
private Schema createSchema(final Source[] schemaSources) {
return createSchema(schemaSources, null);
}
@ -116,11 +126,11 @@ public class ContentRepository {
* @param url die url
* @return das erzeugte Schema
*/
public static Schema createSchema(final URL url) {
public Schema createSchema(final URL url) {
return createSchema(url, null);
}
public static 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());
return createSchema(new Source[] { resolve(url) }, resourceResolver);
}
@ -130,7 +140,7 @@ public class ContentRepository {
*
* @return Scenario-Schema
*/
public static Schema getScenarioSchema() {
public Schema getScenarioSchema() {
return createSchema(ContentRepository.class.getResource("/xsd/scenarios.xsd"));
}
@ -140,11 +150,11 @@ public class ContentRepository {
* @return ReportInput-Schema
*/
public Schema getReportInputSchema() {
if (this.reportInputSchema == null) {
if (reportInputSchema == null) {
final Source source = resolve(ContentRepository.class.getResource("/xsd/createReportInput.xsd"));
this.reportInputSchema = createSchema(new Source[] { source }, new ClassPathResourceResolver("/xsd"));
reportInputSchema = createSchema(new Source[] { source }, new ClassPathResourceResolver("/xsd"));
}
return this.reportInputSchema;
return reportInputSchema;
}
/**
@ -157,8 +167,23 @@ public class ContentRepository {
return createSchema(uris.stream().map(s -> resolve(URI.create(s))).toArray(Source[]::new));
}
/**
* Liefert das Schema zu diesem Szenario.
*
* @return das passende Schema
*/
public Schema createSchema(final ScenarioType s) {
Schema schema = null;
if (s.getValidateWithXmlSchema() != null) {
final List<String> schemaResources = s.getValidateWithXmlSchema().getResource().stream().map(ResourceType::getLocation)
.collect(Collectors.toList());
schema = createSchema(schemaResources);
}
return schema;
}
private Source resolve(final URI source) {
final URI resolved = RelativeUriResolver.resolve(source, this.repository);
final URI resolved = this.mode.resolve(source, this.repository);
return new StreamSource(resolved.toASCIIString());
}
@ -187,7 +212,30 @@ public class ContentRepository {
*
* @return ein neuer Resolver
*/
public RelativeUriResolver createResolver() {
return new RelativeUriResolver(this.repository);
public URIResolver createResolver() {
return this.mode.createResolver(this.repository);
}
/**
* Gibt eine Transformation zurück.
*
* @return initialisierte Transformation
*/
public Transformation createReportTransformation(final ScenarioType t) {
final ResourceType resource = t.getCreateReport().getResource();
final XsltExecutable executable = loadXsltScript(URI.create(resource.getLocation()));
return new Transformation(executable, resource);
}
public XPathExecutable createMatchExecutable(final ScenarioType s) {
final Map<String, String> namespaces = s.getNamespace().stream()
.collect(Collectors.toMap(NamespaceType::getPrefix, NamespaceType::getValue));
return createXPath(s.getMatch(), namespaces);
}
public XPathExecutable createAccepptExecutable(final ScenarioType s) {
final Map<String, String> namespaces = s.getNamespace().stream()
.collect(Collectors.toMap(NamespaceType::getPrefix, NamespaceType::getValue));
return createXPath(s.getAcceptMatch(), namespaces);
}
}

View file

@ -28,7 +28,7 @@ import lombok.Getter;
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.Input;
import de.kosit.validationtool.api.Result;
import de.kosit.validationtool.api.XmlError;
@ -73,20 +73,22 @@ public class DefaultCheck implements Check {
*
* @param configuration die Konfiguration
*/
public DefaultCheck(final CheckConfiguration configuration) {
public DefaultCheck(final Configuration configuration) {
final Processor processor = ObjectFactory.createProcessor();
this.conversionService = new ConversionService();
this.contentRepository = new ContentRepository(processor, configuration.getScenarioRepository());
this.repository = new ScenarioRepository(this.contentRepository);
this.repository.initialize(configuration);
this.repository = new ScenarioRepository(configuration);
// TODO get rid of it
this.contentRepository = configuration.getContentRepository();
this.checkSteps = new ArrayList<>();
this.checkSteps.add(new DocumentParseAction());
this.checkSteps.add(new CreateDocumentIdentificationAction());
this.checkSteps.add(new ScenarioSelectionAction(this.repository));
this.checkSteps.add(new SchemaValidationAction());
this.checkSteps.add(new SchematronValidationAction(this.contentRepository, this.conversionService));
this.checkSteps.add(new ValidateReportInputAction(this.conversionService, this.contentRepository.getReportInputSchema()));
this.checkSteps.add(new CreateReportAction(processor, this.conversionService, this.repository, this.contentRepository));
this.checkSteps
.add(new ValidateReportInputAction(this.conversionService, configuration.getContentRepository().getReportInputSchema()));
this.checkSteps.add(new CreateReportAction(processor, this.conversionService, this.contentRepository));
this.checkSteps.add(new ComputeAcceptanceAction());
}
@ -139,5 +141,4 @@ public class DefaultCheck implements Check {
return (List<XmlError>) (List<?>) errors;
}
}

View file

@ -207,7 +207,7 @@ public class ObjectFactory {
final SecureUriResolver resolver = new SecureUriResolver();
processor.getUnderlyingConfiguration().setCollectionFinder(resolver);
processor.getUnderlyingConfiguration().setOutputURIResolver(resolver);
//hier fehlt eigentlich noch der UriResolver für unparsed text, wird erst ab Saxon 9.8 unterstützt
processor.getUnderlyingConfiguration().setUnparsedTextURIResolver(resolver);
//grundsätzlich Feature-konfiguration:
processor.setConfigurationProperty(FeatureKeys.DTD_VALIDATION, false);

View file

@ -0,0 +1,45 @@
package de.kosit.validationtool.impl;
import java.net.URI;
import javax.xml.transform.URIResolver;
import org.apache.commons.lang3.NotImplementedException;
/**
* Defines how artefacts are resolved internally.
*
* @author Andreas Penski
*/
public enum ResolvingMode {
/**
* Resolving using only the configured content repository. No furthing resolving allowed. This
*/
STRICT_RELATIVE {
@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,
JDK_SUPPORTED,
CUSTOM;
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");
}
}

View file

@ -0,0 +1,83 @@
package de.kosit.validationtool.impl;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import javax.xml.validation.Schema;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import de.kosit.validationtool.model.scenarios.ResourceType;
import de.kosit.validationtool.model.scenarios.ScenarioType;
import net.sf.saxon.s9api.XPathExecutable;
import net.sf.saxon.s9api.XPathSelector;
import net.sf.saxon.s9api.XsltExecutable;
/**
* @author Andreas Penski
*/
@RequiredArgsConstructor
@Setter
@Getter
public class Scenario {
/**
* Runtime objects for a transformation e.g. schematron or report.
*/
@Getter
@Setter
@AllArgsConstructor
public static class Transformation {
private XsltExecutable executable;
private ResourceType resourceType;
}
private final ScenarioType configuration;
private Schema schema;
private boolean fallback;
private XPathExecutable matchExecutable;
private XPathExecutable acceptExecutable;
@Setter
private List<Transformation> schematronValidations;
private Transformation reportTransformation;
public List<Transformation> getSchematronValidations() {
return this.schematronValidations == null ? Collections.emptyList() : this.schematronValidations;
}
public String getName() {
return this.configuration.getName();
}
public XPathSelector getMatchSelector() {
if (this.matchExecutable == null) {
throw new IllegalStateException("No match executable supplied");
}
return this.matchExecutable.load();
}
/**
* Liefert einen neuen XPath-Selector zur Evaluierung der {@link de.kosit.validationtool.api.AcceptRecommendation}.
*
* @return neuer Selector
*/
public Optional<XPathSelector> getAcceptSelector() {
final XPathSelector selector = this.acceptExecutable != null ? this.acceptExecutable.load() : null;
return Optional.ofNullable(selector);
}
}

View file

@ -19,34 +19,18 @@
package de.kosit.validationtool.impl;
import static org.apache.commons.lang3.StringUtils.startsWith;
import java.net.MalformedURLException;
import java.net.URI;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import de.kosit.validationtool.api.CheckConfiguration;
import de.kosit.validationtool.api.InputFactory;
import de.kosit.validationtool.api.Configuration;
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.scenarios.CreateReportType;
import de.kosit.validationtool.model.scenarios.ScenarioType;
import de.kosit.validationtool.model.scenarios.Scenarios;
import net.sf.saxon.s9api.QName;
import net.sf.saxon.s9api.SaxonApiException;
import net.sf.saxon.s9api.XPathSelector;
import net.sf.saxon.s9api.XdmNode;
import net.sf.saxon.s9api.XdmNodeKind;
/**
* Repository for die aktiven Szenario einer Prüfinstanz.
@ -54,86 +38,29 @@ import net.sf.saxon.s9api.XdmNodeKind;
* @author Andreas Penski
*/
@Slf4j
@RequiredArgsConstructor
public class ScenarioRepository {
private static final String SUPPORTED_MAJOR_VERSION = "1";
private final Configuration configuration;
private static final String SUPPORTED_MAJOR_VERSION_SCHEMA = "http://www.xoev.de/de/validator/framework/1/scenarios";
@Getter(value = AccessLevel.PACKAGE)
private final ContentRepository repository;
@Getter
private Scenarios scenarios;
@Setter(AccessLevel.PACKAGE)
@Getter
private ScenarioType fallbackScenario;
private static boolean isSupportedDocument(final XdmNode doc) {
final XdmNode root = findRoot(doc);
final String frameworkVersion = root.getAttributeValue(new QName("frameworkVersion"));
return startsWith(frameworkVersion, SUPPORTED_MAJOR_VERSION)
&& root.getNodeName().getNamespaceURI().equals(SUPPORTED_MAJOR_VERSION_SCHEMA);
public ScenarioRepository(final Configuration configuration) {
this.configuration = configuration;
configuration.build();
log.info("Loaded scenarios for {} by {} from {}. The following scenarios are available:\n\n{}", configuration.getName(),
configuration.getAuthor(), configuration.getDate(), summarizeScenarios());
}
private static XdmNode findRoot(final XdmNode doc) {
for (final XdmNode node : doc.children()) {
if (node.getNodeKind() == XdmNodeKind.ELEMENT) {
return node;
}
}
throw new IllegalArgumentException("Kein root element gefunden");
public Scenario getFallbackScenario() {
return this.configuration.getFallbackScenario();
}
private static void checkVersion(final URI scenarioDefinition) {
final DocumentParseAction p = new DocumentParseAction();
try {
final Result<XdmNode, XMLSyntaxError> result = DocumentParseAction.parseDocument(InputFactory.read(scenarioDefinition.toURL()));
if (result.isValid() && !isSupportedDocument(result.getObject())) {
throw new IllegalStateException(String.format(
"Specified scenario configuration %s is not supported.%nThis version only supports definitions of '%s'",
scenarioDefinition, SUPPORTED_MAJOR_VERSION_SCHEMA));
}
} catch (final MalformedURLException e) {
throw new IllegalStateException("Error reading definition file");
}
}
/**
* Initialisiert das Repository mit der angegebenen Konfiguration.
*
* @param config die Konfiguration
*/
public void initialize(final CheckConfiguration config) {
final ConversionService conversionService = new ConversionService();
checkVersion(config.getScenarioDefinition());
log.info("Loading scenarios from {}", config.getScenarioDefinition());
final CollectingErrorEventHandler handler = new CollectingErrorEventHandler();
this.scenarios = conversionService.readXml(config.getScenarioDefinition(), Scenarios.class, ContentRepository.getScenarioSchema(),
handler);
if (!handler.hasErrors()) {
log.info("Loaded scenarios for {} by {} from {}. The following scenarios are available:\n\n{}", this.scenarios.getName(),
this.scenarios.getAuthor(), this.scenarios.getDate(), summarizeScenarios());
log.info("Loading scenario content from {}", config.getScenarioRepository());
getScenarios().getScenario().forEach(s -> s.initialize(this.repository, false));
} else {
throw new IllegalStateException(String.format("Can not load scenarios from %s due to %s", config.getScenarioDefinition(),
handler.getErrorDescription()));
}
// initialize fallback report eager
this.fallbackScenario = createFallback();
public List<Scenario> getScenarios() {
return this.configuration.getScenarios();
}
private String summarizeScenarios() {
final StringBuilder b = new StringBuilder();
this.scenarios.getScenario().forEach(s -> {
getScenarios().forEach(s -> {
b.append(s.getName());
b.append("\n");
});
@ -146,9 +73,9 @@ public class ScenarioRepository {
* @param document das Eingabedokument
* @return ein Ergebnis-Objekt zur weiteren Verarbeitung
*/
public Result<ScenarioType, String> selectScenario(final XdmNode document) {
final Result<ScenarioType, String> result;
final List<ScenarioType> collect = this.scenarios.getScenario().stream().filter(s -> match(document, s))
public Result<Scenario, String> selectScenario(final XdmNode document) {
final Result<Scenario, String> result;
final List<Scenario> collect = getScenarios().stream().filter(s -> match(document, s))
.collect(Collectors.toList());
if (collect.size() == 1) {
result = new Result<>(collect.get(0));
@ -162,23 +89,9 @@ public class ScenarioRepository {
}
private ScenarioType createFallback() {
final ScenarioType t = new ScenarioType();
t.setFallback(true);
t.setName("Fallback-Scenario");
t.setMatch("count(/)<0");
final CreateReportType reportType = new CreateReportType();
reportType.setResource(this.scenarios.getNoScenarioReport().getResource());
t.initialize(this.repository, true);
// always reject
t.setAcceptMatch("count(/)<0");
t.setCreateReport(reportType);
return t;
}
private static boolean match(final XdmNode document, final ScenarioType scenario) {
private static boolean match(final XdmNode document, final Scenario scenario) {
try {
final XPathSelector selector = scenario.getSelector();
final XPathSelector selector = scenario.getMatchSelector();
selector.setContextItem(document);
return selector.effectiveBooleanValue();
} catch (final SaxonApiException e) {
@ -187,7 +100,4 @@ public class ScenarioRepository {
return false;
}
void initialize(final Scenarios def) {
this.scenarios = def;
}
}

View file

@ -1,224 +0,0 @@
/*
* Licensed to the Koordinierungsstelle für IT-Standards (KoSIT) under
* one or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. KoSIT licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package de.kosit.validationtool.impl.model;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlTransient;
import javax.xml.validation.Schema;
import org.apache.commons.lang3.NotImplementedException;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import de.kosit.validationtool.impl.ContentRepository;
import de.kosit.validationtool.impl.ScenarioRepository;
import de.kosit.validationtool.model.scenarios.CreateReportType;
import de.kosit.validationtool.model.scenarios.NamespaceType;
import de.kosit.validationtool.model.scenarios.ResourceType;
import de.kosit.validationtool.model.scenarios.ValidateWithSchematron;
import de.kosit.validationtool.model.scenarios.ValidateWithXmlSchema;
import net.sf.saxon.s9api.XPathExecutable;
import net.sf.saxon.s9api.XPathSelector;
import net.sf.saxon.s9api.XsltExecutable;
/**
* Eine Basis-Klasse für Szenarien. Wiederverwendbare Objekte mit Bezug zum Szenario werden hier gecached. Die Klasse
* stellt im eigentlichen Sinne eine Erweiterung der durch JAXB generierten Strukturen dar.
*
* @author Andreas Penski
*/
@XmlAccessorType(XmlAccessType.NONE)
public abstract class BaseScenario {
/**
* Laufzeitinformationen über eine Transformation.
*/
@Getter
@Setter
@AllArgsConstructor
public static class Transformation {
private XsltExecutable executable;
private ResourceType resourceType;
}
@XmlTransient
@Getter
@Setter
private boolean fallback;
private XPathExecutable matchExecutable;
private XPathExecutable acceptExecutable;
@Setter
@XmlTransient
private Schema schema;
@Setter
private List<Transformation> schematronValidations;
private ContentRepository repository;
private Transformation reportTransformation;
/**
* Gibt eine Transformation zurück.
*
* @return initialisierte Transformation
*/
public Transformation getReportTransformation() {
if (this.reportTransformation == null) {
final ResourceType resource = getCreateReport().getResource();
final XsltExecutable executable = this.repository.loadXsltScript(URI.create(resource.getLocation()));
this.reportTransformation = new Transformation(executable, resource);
}
return this.reportTransformation;
}
/**
* Lieferrt das Schema zu diesem Szenario.
*
* @return das passende Schema
*/
public Schema getSchema() {
if (this.schema == null && getValidateWithXmlSchema() != null) {
final List<String> schemaResources = getValidateWithXmlSchema().getResource().stream().map(ResourceType::getLocation)
.collect(Collectors.toList());
this.schema = this.repository.createSchema(schemaResources);
}
return this.schema;
}
/**
* Initialisiert das Szenario auf Basis eines [@link ContentRepository}
*
* @param repository das Repository mit den Szenario-Artefakten
* @param lazy optionales lazy loading der XML-Artefakte
* @return true wenn erfolgreich
*/
public boolean initialize(final ContentRepository repository, final boolean lazy) {
this.repository = repository;
if (!lazy) {
getSchema();
getSelector();
getSchematronValidations();
getReportTransformation();
}
return true;
}
/**
* Liefer eine Liste mit Schematron Validierungs-Transformationen.
*
* @return liste mit initialisierten Transformationsinformationen
*/
public List<Transformation> getSchematronValidations() {
if (this.schematronValidations == null) {
this.schematronValidations = new ArrayList<>();
getValidateWithSchematron().forEach(v -> {
if (v.isPsvi()) {
throw new NotImplementedException("This implemenation does not support PSVI usage");
}
final XsltExecutable xsltExecutable = this.repository.loadXsltScript(URI.create(v.getResource().getLocation()));
this.schematronValidations.add(new Transformation(xsltExecutable, v.getResource()));
});
}
return this.schematronValidations;
}
/**
* Der XPath-Selector zur Identifikation des Scenarios.
*
* @return vorbereiteten selector
* @see ScenarioRepository#selectScenario(net.sf.saxon.s9api.XdmNode)
*/
public XPathSelector getSelector() {
if (this.matchExecutable == null) {
this.matchExecutable = this.repository.createXPath(getMatch(), prepareNamespaces());
}
return this.matchExecutable.load();
}
/**
* Liefert einen neuen XPath-Selector zur Evaluierung der {@link de.kosit.validationtool.api.AcceptRecommendation}.
*
* @return neuer Selector
*/
public XPathSelector getAcceptSelector() {
if (this.acceptExecutable == null) {
this.acceptExecutable = this.repository.createXPath(getAcceptMatch(), prepareNamespaces());
}
return this.acceptExecutable.load();
}
private Map<String, String> prepareNamespaces() {
return getNamespace().stream().collect(Collectors.toMap(NamespaceType::getPrefix, NamespaceType::getValue));
}
/**
* Getter aus dem schema.
*
* @return xpath match
*/
public abstract String getMatch();
public abstract String getAcceptMatch();
/**
* Getter aus dem schema.
*
* @return {@link List} of {@link NamespaceType}
*/
public abstract List<NamespaceType> getNamespace();
/**
* Getter aus dem schema.
*
* @return Validierungsanweisungen
*/
public abstract ValidateWithXmlSchema getValidateWithXmlSchema();
/**
* Getter aus dem schema.
*
* @return Validierungsanweisungne
*/
public abstract List<ValidateWithSchematron> getValidateWithSchematron();
/**
* Getter aus dem schema.
*
* @return report informationen
*/
public abstract CreateReportType getCreateReport();
}

View file

@ -30,11 +30,11 @@ import lombok.Setter;
import de.kosit.validationtool.api.AcceptRecommendation;
import de.kosit.validationtool.api.Input;
import de.kosit.validationtool.impl.Scenario;
import de.kosit.validationtool.impl.model.Result;
import de.kosit.validationtool.model.reportInput.CreateReportInput;
import de.kosit.validationtool.model.reportInput.ProcessingError;
import de.kosit.validationtool.model.reportInput.XMLSyntaxError;
import de.kosit.validationtool.model.scenarios.ScenarioType;
import net.sf.saxon.s9api.XdmNode;
@ -55,7 +55,7 @@ public interface CheckAction {
@Setter
class Bag {
private Result<ScenarioType, String> scenarioSelectionResult;
private Result<Scenario, String> scenarioSelectionResult;
@Setter(AccessLevel.NONE)
private CreateReportInput reportInput;

View file

@ -1,6 +1,6 @@
package de.kosit.validationtool.impl.tasks;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.util.Optional;
import org.oclc.purl.dsdl.svrl.FailedAssert;
@ -25,9 +25,9 @@ public class ComputeAcceptanceAction implements CheckAction {
@Override
public void check(final Bag results) {
if (preCondtionsMatch(results)) {
final String acceptMatch = results.getScenarioSelectionResult().getObject().getAcceptMatch();
if (results.getSchemaValidationResult().isValid() && isNotBlank(acceptMatch)) {
evaluateAcceptanceMatch(results);
final Optional<XPathSelector> acceptMatch = results.getScenarioSelectionResult().getObject().getAcceptSelector();
if (results.getSchemaValidationResult().isValid() && acceptMatch.isPresent()) {
evaluateAcceptanceMatch(results, acceptMatch.get());
} else {
evaluateSchemaAndSchematron(results);
}
@ -53,9 +53,8 @@ public class ComputeAcceptanceAction implements CheckAction {
.flatMap(e -> e.getActivePatternAndFiredRuleAndFailedAssert().stream()).anyMatch(FailedAssert.class::isInstance);
}
private static void evaluateAcceptanceMatch(final Bag results) {
private static void evaluateAcceptanceMatch(final Bag results, final XPathSelector selector) {
try {
final XPathSelector selector = results.getScenarioSelectionResult().getObject().getAcceptSelector();
selector.setContextItem(results.getReport());
results.setAcceptStatus(selector.effectiveBooleanValue() ? AcceptRecommendation.ACCEPTABLE : AcceptRecommendation.REJECT);
} catch (final SaxonApiException e) {

View file

@ -22,6 +22,7 @@ package de.kosit.validationtool.impl.tasks;
import java.util.Collection;
import java.util.stream.Collectors;
import javax.xml.transform.URIResolver;
import javax.xml.transform.dom.DOMSource;
import org.w3c.dom.Document;
@ -35,10 +36,8 @@ import de.kosit.validationtool.impl.ContentRepository;
import de.kosit.validationtool.impl.ConversionService;
import de.kosit.validationtool.impl.EngineInformation;
import de.kosit.validationtool.impl.ObjectFactory;
import de.kosit.validationtool.impl.RelativeUriResolver;
import de.kosit.validationtool.impl.ScenarioRepository;
import de.kosit.validationtool.impl.Scenario;
import de.kosit.validationtool.model.reportInput.XMLSyntaxError;
import de.kosit.validationtool.model.scenarios.ScenarioType;
import net.sf.saxon.s9api.BuildingContentHandler;
import net.sf.saxon.s9api.DocumentBuilder;
@ -64,11 +63,9 @@ public class CreateReportAction implements CheckAction {
private final ConversionService conversionService;
private final ScenarioRepository scenarioRepository;
private final ContentRepository contentRepository;
private static XsltExecutable loadFromScenario(final ScenarioType object) {
private static XsltExecutable loadFromScenario(final Scenario object) {
return object.getReportTransformation().getExecutable();
}
@ -85,10 +82,10 @@ public class CreateReportAction implements CheckAction {
final XsltTransformer transformer = getTransformation(results).load();
transformer.setInitialContextNode(root);
final CollectingErrorEventHandler e = new CollectingErrorEventHandler();
final RelativeUriResolver resolver = this.contentRepository.createResolver();
final URIResolver resolver = this.contentRepository.createResolver();
transformer.setMessageListener(e);
transformer.setURIResolver(resolver);
transformer.getUnderlyingController().setUnparsedTextURIResolver(resolver);
// transformer.getUnderlyingController().setUnparsedTextURIResolver(resolver);
if (parsedDocument != null) {
transformer.setParameter(new QName("input-document"), parsedDocument);
}

View file

@ -22,10 +22,10 @@ package de.kosit.validationtool.impl.tasks;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import de.kosit.validationtool.impl.Scenario;
import de.kosit.validationtool.impl.ScenarioRepository;
import de.kosit.validationtool.impl.model.Result;
import de.kosit.validationtool.model.reportInput.CreateReportInput;
import de.kosit.validationtool.model.scenarios.ScenarioType;
import net.sf.saxon.s9api.XdmNode;
@ -44,7 +44,7 @@ public class ScenarioSelectionAction implements CheckAction {
@Override
public void check(final Bag results) {
final CreateReportInput report = results.getReportInput();
final Result<ScenarioType, String> scenarioTypeResult;
final Result<Scenario, String> scenarioTypeResult;
if (results.getParserResult().isValid()) {
scenarioTypeResult = determineScenario(results.getParserResult().getObject());
@ -53,15 +53,15 @@ public class ScenarioSelectionAction implements CheckAction {
}
results.setScenarioSelectionResult(scenarioTypeResult);
if (!scenarioTypeResult.getObject().isFallback()) {
report.setScenario(scenarioTypeResult.getObject());
report.setScenario(scenarioTypeResult.getObject().getConfiguration());
log.info("Schenario {} identified for {}", scenarioTypeResult.getObject().getName(), results.getInput().getName());
} else {
log.error("No valid schenario configuration found for {}", results.getInput().getName());
}
}
private Result<ScenarioType, String> determineScenario(final XdmNode document) {
final Result<ScenarioType, String> result = this.repository.selectScenario(document);
private Result<Scenario, String> determineScenario(final XdmNode document) {
final Result<Scenario, String> result = this.repository.selectScenario(document);
if (result.isInvalid()) {
return new Result<>(this.repository.getFallbackScenario());
}

View file

@ -42,12 +42,12 @@ import lombok.extern.slf4j.Slf4j;
import de.kosit.validationtool.api.Input;
import de.kosit.validationtool.impl.CollectingErrorEventHandler;
import de.kosit.validationtool.impl.ObjectFactory;
import de.kosit.validationtool.impl.Scenario;
import de.kosit.validationtool.impl.input.AbstractInput;
import de.kosit.validationtool.impl.model.Result;
import de.kosit.validationtool.model.reportInput.CreateReportInput;
import de.kosit.validationtool.model.reportInput.ValidationResultsXmlSchema;
import de.kosit.validationtool.model.reportInput.XMLSyntaxError;
import de.kosit.validationtool.model.scenarios.ScenarioType;
import net.sf.saxon.s9api.SaxonApiException;
import net.sf.saxon.s9api.Serializer;
@ -132,17 +132,17 @@ public class SchemaValidationAction implements CheckAction {
@Getter
private long inMemoryLimit = Long.parseLong(System.getProperty(LIMIT_PARAMETER, BA_LIMIT.toString())) * FileUtils.ONE_MB;
private Result<Boolean, XMLSyntaxError> validate(final Bag results, final ScenarioType scenarioType) {
log.debug("Validating document using scenario {}", scenarioType.getName());
private Result<Boolean, XMLSyntaxError> validate(final Bag results, final Scenario scenario) {
log.debug("Validating document using scenario {}", scenario.getConfiguration().getName());
final CollectingErrorEventHandler errorHandler = new CollectingErrorEventHandler();
try ( final SourceProvider validateInput = resolveSource(results) ) {
final Validator validator = ObjectFactory.createValidator(scenarioType.getSchema());
final Validator validator = ObjectFactory.createValidator(scenario.getSchema());
validator.setErrorHandler(errorHandler);
validator.validate(validateInput.getSource());
return new Result<>(!errorHandler.hasErrors(), errorHandler.getErrors());
} catch (final SAXException | SaxonApiException | IOException e) {
final String msg = String.format("Error processing schema validation for scenario %s", scenarioType.getName());
final String msg = String.format("Error processing schema validation for scenario %s", scenario.getConfiguration().getName());
log.error(msg, e);
results.addProcessingError(msg);
return new Result<>(Boolean.FALSE);
@ -152,14 +152,14 @@ public class SchemaValidationAction implements CheckAction {
@Override
public void check(final Bag results) {
final CreateReportInput report = results.getReportInput();
final ScenarioType scenario = results.getScenarioSelectionResult().getObject();
final Scenario scenario = results.getScenarioSelectionResult().getObject();
final Result<Boolean, XMLSyntaxError> validateResult = validate(results, scenario);
results.setSchemaValidationResult(validateResult);
final ValidationResultsXmlSchema result = new ValidationResultsXmlSchema();
report.setValidationResultsXmlSchema(result);
result.getResource().addAll(scenario.getValidateWithXmlSchema().getResource());
result.getResource().addAll(scenario.getConfiguration().getValidateWithXmlSchema().getResource());
if (!validateResult.isValid()) {
result.getXmlSyntaxError().addAll(validateResult.getErrors());
}

View file

@ -22,6 +22,7 @@ package de.kosit.validationtool.impl.tasks;
import java.util.List;
import java.util.stream.Collectors;
import javax.xml.transform.URIResolver;
import javax.xml.transform.dom.DOMSource;
import org.oclc.purl.dsdl.svrl.SchematronOutput;
@ -34,11 +35,9 @@ import de.kosit.validationtool.impl.CollectingErrorEventHandler;
import de.kosit.validationtool.impl.ContentRepository;
import de.kosit.validationtool.impl.ConversionService;
import de.kosit.validationtool.impl.ObjectFactory;
import de.kosit.validationtool.impl.RelativeUriResolver;
import de.kosit.validationtool.impl.model.BaseScenario;
import de.kosit.validationtool.impl.Scenario;
import de.kosit.validationtool.model.reportInput.CreateReportInput;
import de.kosit.validationtool.model.reportInput.ValidationResultsSchematron;
import de.kosit.validationtool.model.scenarios.ScenarioType;
import net.sf.saxon.s9api.DOMDestination;
import net.sf.saxon.s9api.SaxonApiException;
@ -58,17 +57,17 @@ public class SchematronValidationAction implements CheckAction {
private final ConversionService conversionService;
private List<ValidationResultsSchematron> validate(final Bag results, final XdmNode document, final ScenarioType scenario) {
private List<ValidationResultsSchematron> validate(final Bag results, final XdmNode document, final Scenario scenario) {
return scenario.getSchematronValidations().stream().map(v -> validate(results, document, v)).collect(Collectors.toList());
}
private ValidationResultsSchematron validate(final Bag results, final XdmNode document, final BaseScenario.Transformation validation) {
private ValidationResultsSchematron validate(final Bag results, final XdmNode document, final Scenario.Transformation validation) {
final ValidationResultsSchematron s = new ValidationResultsSchematron();
s.setResource(validation.getResourceType());
try {
final XsltTransformer transformer = validation.getExecutable().load();
// resolving nur relative zum Repository
final RelativeUriResolver resolver = this.repository.createResolver();
final URIResolver resolver = this.repository.createResolver();
transformer.setURIResolver(resolver);
final CollectingErrorEventHandler e = new CollectingErrorEventHandler();
transformer.setMessageListener(e);
@ -107,7 +106,7 @@ public class SchematronValidationAction implements CheckAction {
return results.getSchemaValidationResult() == null || results.getSchemaValidationResult().isInvalid();
}
private static boolean hasNoSchematrons(final ScenarioType object) {
return object.getValidateWithSchematron() == null || object.getValidateWithSchematron().size() == 0;
private static boolean hasNoSchematrons(final Scenario object) {
return object.getSchematronValidations().isEmpty();
}
}

View file

@ -42,9 +42,6 @@
<jaxb:schemaBindings>
<jaxb:package name="de.kosit.validationtool.model.scenarios"/>
</jaxb:schemaBindings>
<jaxb:bindings node="//xs:complexType[@name='ScenarioType']">
<inheritance:extends>de.kosit.validationtool.impl.model.BaseScenario</inheritance:extends>
</jaxb:bindings>
</jaxb:bindings>
<jaxb:bindings schemaLocation="../xsd/assertions.xsd">
<jaxb:schemaBindings>