mirror of
https://github.com/itplr-kosit/validator.git
synced 2026-05-26 01:05:38 +00:00
Verzeichnisstruktur erweitert, um Prüftool und Konfiguration XRechnung aufzunehmen.
This commit is contained in:
parent
0fd87014b4
commit
4eab984c01
161 changed files with 106853 additions and 11 deletions
|
|
@ -1,118 +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;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.w3c.dom.ls.LSInput;
|
||||
import org.w3c.dom.ls.LSResourceResolver;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* {@link LSResourceResolver} der objekte relativ zu einem Basis-Pfad aus dem Classpath der Anwendung laden kann.
|
||||
*
|
||||
* @author Andreas Penski
|
||||
*/
|
||||
@Slf4j
|
||||
class ClassPathResourceResolver implements LSResourceResolver {
|
||||
|
||||
private final URI base;
|
||||
|
||||
/**
|
||||
* Instantiiert einen neuen resolver mit angegebenen Basispfad
|
||||
*
|
||||
* @param basePath der Basispfad
|
||||
*/
|
||||
public ClassPathResourceResolver(String basePath) {
|
||||
if (!StringUtils.startsWith(basePath, "/")) {
|
||||
throw new IllegalArgumentException("Base path must start with a slash");
|
||||
}
|
||||
base = URI.create(basePath + (basePath.endsWith("/") == basePath.length() > 1 ? "" : "/"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public LSInput resolveResource(String type, String namespaceURI, String publicId, String systemId, String baseURI) {
|
||||
final URL resource = ClassPathResourceResolver.class.getResource(base.resolve(systemId).toASCIIString());
|
||||
if (resource != null) {
|
||||
try {
|
||||
InputStream in = resource.openStream();
|
||||
final LSInputImpl input = new LSInputImpl(publicId, systemId, baseURI);
|
||||
input.setByteStream(in);
|
||||
return input;
|
||||
|
||||
} catch (IOException e) {
|
||||
log.error("Error loading schema resource from {}", resource, e);
|
||||
}
|
||||
}
|
||||
// not found
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple {@link LSInput}-Implementierung, die einen Stream liefern kann
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@RequiredArgsConstructor
|
||||
private static class LSInputImpl implements LSInput {
|
||||
|
||||
private Reader characterStream;
|
||||
|
||||
private InputStream byteStream;
|
||||
|
||||
private String systemId;
|
||||
|
||||
private String publicId;
|
||||
|
||||
private String baseURI;
|
||||
|
||||
private String encoding;
|
||||
|
||||
private boolean certifiedText;
|
||||
|
||||
private String stringData;
|
||||
|
||||
/**
|
||||
* Instantiierung einer neue Instanz.
|
||||
* @param publicId die publicId
|
||||
* @param systemId die systemId
|
||||
* @param baseURI die baseURI
|
||||
*/
|
||||
public LSInputImpl(String publicId, String systemId, String baseURI) {
|
||||
this.publicId = publicId;
|
||||
this.systemId = systemId;
|
||||
this.baseURI = baseURI;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getCertifiedText() {
|
||||
return certifiedText;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,168 +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;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.StringJoiner;
|
||||
|
||||
import javax.xml.bind.ValidationEvent;
|
||||
import javax.xml.bind.ValidationEventHandler;
|
||||
import javax.xml.transform.ErrorListener;
|
||||
import javax.xml.transform.SourceLocator;
|
||||
import javax.xml.transform.TransformerException;
|
||||
|
||||
import org.xml.sax.ErrorHandler;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.SAXParseException;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
import de.kosit.validationtool.model.reportInput.XMLSyntaxError;
|
||||
import de.kosit.validationtool.model.reportInput.XMLSyntaxErrorSeverity;
|
||||
|
||||
import net.sf.saxon.s9api.MessageListener;
|
||||
import net.sf.saxon.s9api.XdmNode;
|
||||
|
||||
/**
|
||||
* Sammelt Fehler-Ereignisinformation beim Schema-Validieren und weiteren XML-basierten Aktionen
|
||||
*
|
||||
* @author Andreas Penski
|
||||
*/
|
||||
@Getter
|
||||
public class CollectingErrorEventHandler implements ValidationEventHandler, ErrorHandler, MessageListener, ErrorListener {
|
||||
|
||||
private static final int DEFAULT_ABORT_COUNT = 50;
|
||||
|
||||
private Collection<XMLSyntaxError> errors = new ArrayList<>();
|
||||
|
||||
private int stopProcessCount = DEFAULT_ABORT_COUNT;
|
||||
|
||||
private static XMLSyntaxError createError(XMLSyntaxErrorSeverity severity, String message) {
|
||||
XMLSyntaxError e = new XMLSyntaxError();
|
||||
e.setSeverity(severity);
|
||||
e.setMessage(message);
|
||||
return e;
|
||||
}
|
||||
|
||||
private static XMLSyntaxError createError(XMLSyntaxErrorSeverity severity, SAXParseException exception) {
|
||||
XMLSyntaxError e = createError(severity, exception.getMessage());
|
||||
e.setRowNumber(exception.getLineNumber());
|
||||
e.setColumnNumber(exception.getColumnNumber());
|
||||
return e;
|
||||
}
|
||||
|
||||
private static XMLSyntaxError createError(XMLSyntaxErrorSeverity severity, TransformerException exception) {
|
||||
XMLSyntaxError e = createError(severity, exception.getMessage());
|
||||
if (exception.getLocator() != null) {
|
||||
e.setRowNumber(exception.getLocator().getLineNumber());
|
||||
e.setColumnNumber(exception.getLocator().getColumnNumber());
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
private static XMLSyntaxErrorSeverity translateSeverity(int severity) {
|
||||
switch (severity) {
|
||||
case ValidationEvent.WARNING:
|
||||
return XMLSyntaxErrorSeverity.SEVERITY_WARNING;
|
||||
case ValidationEvent.ERROR:
|
||||
return XMLSyntaxErrorSeverity.SEVERITY_ERROR;
|
||||
case ValidationEvent.FATAL_ERROR:
|
||||
return XMLSyntaxErrorSeverity.SEVERITY_FATAL_ERROR;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown severity level " + severity);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleEvent(ValidationEvent event) {
|
||||
XMLSyntaxError e = createError(translateSeverity(event.getSeverity()), event.getMessage());
|
||||
e.setColumnNumber(event.getLocator().getColumnNumber());
|
||||
e.setRowNumber(event.getLocator().getLineNumber());
|
||||
errors.add(e);
|
||||
return stopProcessCount != errors.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Zeigt an, ob Validierungsfehler vorhanden sind.
|
||||
*
|
||||
* @return true wenn mindestens ein Fehler vorhanden ist.
|
||||
*/
|
||||
public boolean hasErrors() {
|
||||
return hasEvents() && errors.stream().anyMatch(e -> e.getSeverity() != XMLSyntaxErrorSeverity.SEVERITY_WARNING);
|
||||
}
|
||||
|
||||
/**
|
||||
* Zeigt an, ob es Validierungs-Ereignisse gab.
|
||||
*
|
||||
* @return true wenn mindestens ein Validierungsereignis aufgetreten ist
|
||||
*/
|
||||
public boolean hasEvents() {
|
||||
return !errors.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warning(SAXParseException exception) throws SAXException {
|
||||
errors.add(createError(XMLSyntaxErrorSeverity.SEVERITY_WARNING, exception));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(SAXParseException exception) throws SAXException {
|
||||
errors.add(createError(XMLSyntaxErrorSeverity.SEVERITY_ERROR, exception));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fatalError(SAXParseException exception) throws SAXException {
|
||||
errors.add(createError(XMLSyntaxErrorSeverity.SEVERITY_FATAL_ERROR, exception));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void message(XdmNode content, boolean terminate, SourceLocator locator) {
|
||||
XMLSyntaxError e = new XMLSyntaxError();
|
||||
if (locator != null) {
|
||||
e.setColumnNumber(locator.getColumnNumber());
|
||||
e.setRowNumber(locator.getLineNumber());
|
||||
}
|
||||
e.setMessage("Error procesing" + content.getStringValue());
|
||||
e.setSeverity(terminate ? XMLSyntaxErrorSeverity.SEVERITY_FATAL_ERROR : XMLSyntaxErrorSeverity.SEVERITY_WARNING);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warning(TransformerException exception) throws TransformerException {
|
||||
errors.add(createError(XMLSyntaxErrorSeverity.SEVERITY_WARNING, exception));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(TransformerException exception) throws TransformerException {
|
||||
errors.add(createError(XMLSyntaxErrorSeverity.SEVERITY_ERROR, exception));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fatalError(TransformerException exception) throws TransformerException {
|
||||
errors.add(createError(XMLSyntaxErrorSeverity.SEVERITY_FATAL_ERROR, exception));
|
||||
}
|
||||
|
||||
public String getErrorDescription() {
|
||||
final StringJoiner joiner = new StringJoiner("\n");
|
||||
errors.forEach(e -> joiner
|
||||
.add(e.getSeverity().value() + " " + e.getMessage() + " At row " + e.getRowNumber() + " at pos " + e.getColumnNumber()));
|
||||
return joiner.toString();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,175 +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;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.xml.transform.Source;
|
||||
import javax.xml.transform.stream.StreamSource;
|
||||
import javax.xml.validation.Schema;
|
||||
import javax.xml.validation.SchemaFactory;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.w3c.dom.ls.LSResourceResolver;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import net.sf.saxon.s9api.*;
|
||||
|
||||
/**
|
||||
* Repository für verschiedene XML Artefakte zur Vearbeitung der Prüfszenarien.
|
||||
*
|
||||
* @author Andreas Penski
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class ContentRepository {
|
||||
|
||||
@Getter
|
||||
private final Processor processor;
|
||||
|
||||
private final URI repository;
|
||||
|
||||
private Schema reportInputSchema;
|
||||
|
||||
private static Source resolve(URL resource) {
|
||||
try {
|
||||
return new StreamSource(resource.openStream(), resource.toURI().getRawPath());
|
||||
} catch (IOException | URISyntaxException e) {
|
||||
throw new IllegalStateException("Can not load schema for resource " + resource.getPath(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private static Schema createSchema(Source[] schemaSources, LSResourceResolver resourceResolver) {
|
||||
try {
|
||||
SchemaFactory sf = ObjectFactory.createSchemaFactory();
|
||||
sf.setResourceResolver(resourceResolver);
|
||||
return sf.newSchema(schemaSources);
|
||||
} catch (SAXException e) {
|
||||
throw new IllegalArgumentException("Can not load schema from sources " + schemaSources[0].getSystemId(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private static Schema createSchema(Source[] schemaSources) {
|
||||
return createSchema(schemaSources, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Lädt ein XSL von der angegebenen URI
|
||||
*
|
||||
* @param uri die URI der XSL Definition
|
||||
* @return ein XSLT Executable
|
||||
*/
|
||||
public XsltExecutable loadXsltScript(URI uri) {
|
||||
log.info("Loading XSLT script from {}", uri);
|
||||
final XsltCompiler xsltCompiler = getProcessor().newXsltCompiler();
|
||||
final CollectingErrorEventHandler listener = new CollectingErrorEventHandler();
|
||||
try {
|
||||
xsltCompiler.setErrorListener(listener);
|
||||
xsltCompiler.setURIResolver(new RelativeUriResolver(repository));
|
||||
|
||||
return xsltCompiler.compile(resolve(uri));
|
||||
} catch (SaxonApiException e) {
|
||||
listener.getErrors().forEach(event -> event.log(log));
|
||||
throw new IllegalStateException("Can not compile xslt executable for uri " + uri, e);
|
||||
} finally {
|
||||
if (!listener.hasErrors() && listener.hasEvents()) {
|
||||
log.warn("Received warnings while loading a xslt script {}", uri);
|
||||
listener.getErrors().forEach(e -> e.log(log));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Erzeugt ein Schema-Objekt auf Basis der übergebenen URL.
|
||||
*
|
||||
* @param url die url
|
||||
* @return das erzeugte Schema
|
||||
*/
|
||||
public Schema createSchema(URL url) {
|
||||
log.info("Load schema from source {}", url.getPath());
|
||||
return createSchema(new Source[] { resolve(url) });
|
||||
}
|
||||
|
||||
/**
|
||||
* Liefert das definiert Schema für die Szenario-Konfiguration
|
||||
*
|
||||
* @return Scenario-Schema
|
||||
*/
|
||||
public Schema getScenarioSchema() {
|
||||
return createSchema(ContentRepository.class.getResource("/xsd/scenarios.xsd"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Liefert das definierte Schema für die Validierung des [@link CreateReportInput}
|
||||
*
|
||||
* @return ReportInput-Schema
|
||||
*/
|
||||
public Schema getReportInputSchema() {
|
||||
if (reportInputSchema == null) {
|
||||
final Source source = resolve(ContentRepository.class.getResource("/xsd/createReportInput.xsd"));
|
||||
reportInputSchema = createSchema(new Source[] { source }, new ClassPathResourceResolver("/xsd"));
|
||||
}
|
||||
return reportInputSchema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Erzeugt ein Schema auf Basis der übegebenen URIs
|
||||
*
|
||||
* @param uris die uris in String-Repräsentation
|
||||
* @return das Schema
|
||||
*/
|
||||
public Schema createSchema(Collection<String> uris) {
|
||||
return createSchema(uris.stream().map(s -> resolve(URI.create(s))).toArray(Source[]::new));
|
||||
}
|
||||
|
||||
private Source resolve(URI source) {
|
||||
return new StreamSource(repository.resolve(source).toASCIIString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Erzeugt einen [@link XPathExecutable} auf Basis der angegebenen Informationen.
|
||||
*
|
||||
* @param expression der XPATH-Ausdruck
|
||||
* @param namespaces optionale Namespace-Mappings
|
||||
* @return ein kompiliertes Executable
|
||||
*/
|
||||
public XPathExecutable createXPath(String expression, Map<String, String> namespaces) {
|
||||
try {
|
||||
final XPathCompiler compiler = getProcessor().newXPathCompiler();
|
||||
if (namespaces != null) {
|
||||
namespaces.entrySet().forEach(n -> compiler.declareNamespace(n.getKey(), n.getValue()));
|
||||
}
|
||||
return compiler.compile(expression);
|
||||
} catch (SaxonApiException e) {
|
||||
throw new IllegalStateException(String.format("Can not compile xpath match expression '%s'",
|
||||
StringUtils.isNotBlank(expression) ? expression : "EMPTY EXPRESSION"), e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,241 +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;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.StringJoiner;
|
||||
|
||||
import javax.xml.bind.*;
|
||||
import javax.xml.bind.annotation.XmlRegistry;
|
||||
import javax.xml.namespace.QName;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.stream.*;
|
||||
import javax.xml.transform.stream.StreamSource;
|
||||
import javax.xml.validation.Schema;
|
||||
|
||||
import org.w3c.dom.Document;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* JAXB Conversion Utility.
|
||||
*/
|
||||
@Slf4j
|
||||
public class ConversionService {
|
||||
|
||||
// context setup
|
||||
private JAXBContext jaxbContext;
|
||||
|
||||
private static <T> QName createQName(final T model) {
|
||||
return new QName(model.getClass().getSimpleName().toLowerCase());
|
||||
}
|
||||
|
||||
private void checkInputEmpty(final URI xml) {
|
||||
if (xml == null) {
|
||||
throw new ConversionExeption("Can not unmarshal from empty input");
|
||||
}
|
||||
}
|
||||
|
||||
private <T> void checkTypeEmpty(final Class<T> type) {
|
||||
if (type == null) {
|
||||
throw new ConversionExeption("Can not unmarshal without type information. Need to specify a target type");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialisiert den default context; Alle Packages mit {@link XmlRegistry XmlRegistries}.
|
||||
*/
|
||||
public void initialize() {
|
||||
Collection<Package> p = new ArrayList<>();
|
||||
p.add(de.kosit.validationtool.model.reportInput.ObjectFactory.class.getPackage());
|
||||
p.add(de.kosit.validationtool.model.scenarios.ObjectFactory.class.getPackage());
|
||||
initialize(p);
|
||||
}
|
||||
|
||||
public void initialize(final Package... context) {
|
||||
initialize(Arrays.asList(context));
|
||||
}
|
||||
/**
|
||||
* Initialisiert den conversion service mit den angegegebenen Packages.
|
||||
*
|
||||
* @param context packages für den JAXB Kontext
|
||||
*/
|
||||
public void initialize(final Collection<Package> context) {
|
||||
final String[] packages = context != null ? context.stream().map(Package::getName).toArray(String[]::new) : new String[0];
|
||||
StringJoiner joiner = new StringJoiner(":");
|
||||
Arrays.stream(packages).forEach(p -> joiner.add(p));
|
||||
initialize(joiner.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialsiert den conversion service mit dem angegebenen Kontextpfad
|
||||
*
|
||||
* @param contextPath der Kontextpfad
|
||||
*/
|
||||
private void initialize(final String contextPath) {
|
||||
try {
|
||||
this.jaxbContext = JAXBContext.newInstance(contextPath);
|
||||
} catch (final JAXBException e) {
|
||||
throw new IllegalStateException(String.format("Can not create JAXB context for given context: %s", contextPath), e);
|
||||
}
|
||||
}
|
||||
|
||||
private JAXBContext getJaxbContext() {
|
||||
if (this.jaxbContext == null) {
|
||||
initialize();
|
||||
}
|
||||
return this.jaxbContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unmarshalls a specifc xml model into a defined java object.
|
||||
*
|
||||
* @param xml the xml
|
||||
* @param type the expected type created
|
||||
* @param <T> type information
|
||||
* @return the created object
|
||||
*/
|
||||
public <T> T readXml(final URI xml, final Class<T> type) {
|
||||
return readXml(xml, type, null, null);
|
||||
}
|
||||
|
||||
public <T> T readXml(final URI xml, final Class<T> type, Schema schema) {
|
||||
return readXml(xml, type, schema, null);
|
||||
}
|
||||
|
||||
public <T> T readXml(final URI xml, final Class<T> type, Schema schema, ValidationEventHandler handler) {
|
||||
checkInputEmpty(xml);
|
||||
checkTypeEmpty(type);
|
||||
CollectingErrorEventHandler defaultHandler = null;
|
||||
ValidationEventHandler handler2Use = handler;
|
||||
if (schema != null && handler == null) {
|
||||
defaultHandler = new CollectingErrorEventHandler();
|
||||
handler2Use = defaultHandler;
|
||||
}
|
||||
try {
|
||||
final XMLInputFactory inputFactory = XMLInputFactory.newFactory();
|
||||
inputFactory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
|
||||
inputFactory.setProperty(XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES, false);
|
||||
inputFactory.setProperty(XMLInputFactory.SUPPORT_DTD, false);
|
||||
final XMLStreamReader xsr = inputFactory.createXMLStreamReader(new StreamSource(xml.toASCIIString()));
|
||||
final Unmarshaller u = getJaxbContext().createUnmarshaller();
|
||||
u.setSchema(schema);
|
||||
|
||||
u.setEventHandler(handler2Use);
|
||||
final T value = u.unmarshal(xsr, type).getValue();
|
||||
if (defaultHandler != null && defaultHandler.hasErrors()) {
|
||||
throw new ConversionExeption(
|
||||
String.format("Schema errors while reading content from %s: %s", xml, defaultHandler.getErrorDescription()));
|
||||
}
|
||||
|
||||
return value;
|
||||
} catch (final JAXBException | XMLStreamException e) {
|
||||
throw new ConversionExeption(String.format("Can not unmarshal to type %s from %s", type.getSimpleName(), xml.toString()), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializing an object to xml.
|
||||
*
|
||||
* @param model the object
|
||||
* @param <T> type of the object
|
||||
* @return the serialized form.
|
||||
*/
|
||||
public <T> String writeXml(final T model) {
|
||||
return writeXml(model, null, null);
|
||||
}
|
||||
|
||||
public <T> String writeXml(final T model, Schema schema, ValidationEventHandler handler) {
|
||||
if (model == null) {
|
||||
throw new ConversionExeption("Can not serialize null");
|
||||
}
|
||||
try ( StringWriter w = new StringWriter() ) {
|
||||
final JAXBIntrospector introspector = getJaxbContext().createJAXBIntrospector();
|
||||
final Marshaller marshaller = getJaxbContext().createMarshaller();
|
||||
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
|
||||
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
|
||||
marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
|
||||
marshaller.setSchema(schema);
|
||||
marshaller.setEventHandler(handler);
|
||||
final XMLOutputFactory xof = XMLOutputFactory.newFactory();
|
||||
final XMLStreamWriter xmlStreamWriter = xof.createXMLStreamWriter(w);
|
||||
if (null == introspector.getElementName(model)) {
|
||||
final JAXBElement jaxbElement = new JAXBElement(createQName(model), model.getClass(), model);
|
||||
marshaller.marshal(jaxbElement, xmlStreamWriter);
|
||||
} else {
|
||||
marshaller.marshal(model, xmlStreamWriter);
|
||||
}
|
||||
xmlStreamWriter.flush();
|
||||
return w.toString();
|
||||
} catch (JAXBException | IOException | XMLStreamException e) {
|
||||
throw new ConversionExeption(String.format("Error serializing Object %s", model.getClass().getName()), e);
|
||||
}
|
||||
}
|
||||
|
||||
public <T> Document writeDocument(T input) {
|
||||
if (input == null) {
|
||||
throw new ConversionExeption("Can not serialize null");
|
||||
}
|
||||
DocumentBuilder builder = ObjectFactory.createDocumentBuilder(false);
|
||||
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 (JAXBException e) {
|
||||
throw new ConversionExeption(String.format("Error serializing Object %s to document", input.getClass().getName()), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Exception while serializing/deserializing with jaxb.
|
||||
*/
|
||||
public class ConversionExeption extends RuntimeException {
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param message the message.
|
||||
* @param cause the cause
|
||||
*/
|
||||
public ConversionExeption(final String message, final Exception cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param message the message.
|
||||
*/
|
||||
public ConversionExeption(final String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,137 +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;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.w3c.dom.Document;
|
||||
|
||||
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.Input;
|
||||
import de.kosit.validationtool.impl.tasks.*;
|
||||
import de.kosit.validationtool.model.reportInput.CreateReportInput;
|
||||
import de.kosit.validationtool.model.reportInput.DocumentIdentificationType;
|
||||
import de.kosit.validationtool.model.reportInput.EngineType;
|
||||
import de.kosit.validationtool.model.reportInput.ProcessingError;
|
||||
|
||||
import net.sf.saxon.s9api.Processor;
|
||||
|
||||
/**
|
||||
* Die Referenz-Implementierung für den Prüfprozess. Nach initialer Konfiguration ist diese Klasse threadsafe und kann
|
||||
* in Server-Umgebungen eingesetzt werden
|
||||
*
|
||||
* @author Andreas Penski
|
||||
*/
|
||||
@Slf4j
|
||||
public class DefaultCheck implements Check {
|
||||
|
||||
private static final String ENGINE_NAME = "KoSIT Prüftool";
|
||||
|
||||
private static final String ENGINE_VERSION = "1.0.0";
|
||||
|
||||
private ScenarioRepository repository;
|
||||
|
||||
@Getter
|
||||
private ContentRepository contentRepository;
|
||||
|
||||
private ConversionService conversionService;
|
||||
|
||||
@Getter
|
||||
private List<CheckAction> checkSteps;
|
||||
|
||||
/**
|
||||
* Erzeugt eine neue Instanz mit der angegebenen Konfiguration.
|
||||
*
|
||||
* @param configuration die Konfiguration
|
||||
*/
|
||||
public DefaultCheck(CheckConfiguration configuration) {
|
||||
Processor processor = ObjectFactory.createProcessor();
|
||||
conversionService = new ConversionService();
|
||||
contentRepository = new ContentRepository(processor, configuration.getScenarioRepository());
|
||||
repository = new ScenarioRepository(processor, contentRepository);
|
||||
repository.initialize(configuration);
|
||||
checkSteps = new ArrayList<>();
|
||||
checkSteps.add(this::createDocumentIdentification);
|
||||
checkSteps.add(new DocumentParseAction());
|
||||
checkSteps.add(new ScenarioSelectionAction(repository));
|
||||
checkSteps.add(new SchemaValidationAction());
|
||||
checkSteps.add(new SchematronValidationAction(processor, configuration.getScenarioRepository()));
|
||||
checkSteps.add(new ValidateReportInputAction(conversionService, contentRepository.getReportInputSchema()));
|
||||
checkSteps.add(new CreateReportAction(processor, conversionService, repository, configuration.getScenarioRepository()));
|
||||
}
|
||||
|
||||
protected static CreateReportInput createReport() {
|
||||
CreateReportInput type = new CreateReportInput();
|
||||
EngineType e = new EngineType();
|
||||
e.setName(ENGINE_NAME);
|
||||
type.setEngine(e);
|
||||
type.setTimestamp(ObjectFactory.createTimestamp());
|
||||
type.setFrameworkVersion(ENGINE_VERSION);
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Document check(Input input) {
|
||||
CheckAction.Bag t = new CheckAction.Bag(input, createReport());
|
||||
return runCheckInternal(t);
|
||||
}
|
||||
|
||||
protected Document runCheckInternal(CheckAction.Bag t) {
|
||||
long started = System.currentTimeMillis();
|
||||
log.info("Checking content of {}", t.getInput().getName());
|
||||
Iterator<CheckAction> it = checkSteps.iterator();
|
||||
|
||||
|
||||
while (it.hasNext()) {
|
||||
final CheckAction action = it.next();
|
||||
if (!action.isSkipped(t)) {
|
||||
action.check(t);
|
||||
}
|
||||
if (t.isStopped()) {
|
||||
final ProcessingError processingError = t.getReportInput().getProcessingError();
|
||||
log.error("Error processing input {}: {}", t.getInput().getName(),
|
||||
processingError != null ? processingError.getError().stream().collect(Collectors.joining("\n")) : "");
|
||||
break;
|
||||
}
|
||||
}
|
||||
t.setFinished(true);
|
||||
log.info("Finished check of {} in {}ms\n", t.getInput().getName(), System.currentTimeMillis() - started);
|
||||
return t.getReport();
|
||||
}
|
||||
|
||||
private boolean createDocumentIdentification(CheckAction.Bag transporter) {
|
||||
DocumentIdentificationType i = new DocumentIdentificationType();
|
||||
DocumentIdentificationType.DocumentHash h = new DocumentIdentificationType.DocumentHash();
|
||||
h.setHashAlgorithm(transporter.getInput().getDigestAlgorithm());
|
||||
h.setHashValue(transporter.getInput().getHashCode());
|
||||
i.setDocumentHash(h);
|
||||
i.setDocumentReference(transporter.getInput().getName());
|
||||
transporter.getReportInput().setDocumentIdentification(i);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,256 +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;
|
||||
|
||||
import java.io.Reader;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URI;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
|
||||
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.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.transform.*;
|
||||
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 net.sf.saxon.Configuration;
|
||||
import net.sf.saxon.expr.XPathContext;
|
||||
import net.sf.saxon.lib.*;
|
||||
import net.sf.saxon.s9api.Processor;
|
||||
import net.sf.saxon.trans.XPathException;
|
||||
|
||||
/**
|
||||
* Eine Factory für häufig verwendete Objekte mit XML. Zentralisiert die XML Security Konfiguration. Die Konfiguration
|
||||
* basiert auf den <a href="https://www.owasp.org/index.php/XML_Security_Cheat_Sheet">OWASP-Empfehlungen</a>.
|
||||
*
|
||||
* Diese Klasse ist stark abhängig von der Verwendung eines Oracle JDK. Alternative JDKs haben u.U. eine andere SAX- /
|
||||
* StAX- / XML-Implementierug und profitieren entsprechend NICHT von den hier getroffenen Einstellungen.
|
||||
*
|
||||
* @author Andreas Penski
|
||||
*/
|
||||
@Slf4j
|
||||
public class ObjectFactory {
|
||||
|
||||
private static final String ORACLE_XERCES_CLASS = "com.sun.org.apache.xerces.internal.impl.Constants";
|
||||
|
||||
private static final String DISSALLOW_DOCTYPE_DECL_FEATURE = "http://apache.org/xml/features/disallow-doctype-decl";
|
||||
|
||||
private static final String LOAD_EXTERNAL_DTD_FEATURE = "http://apache.org/xml/features/nonvalidating/load-external-dtd";
|
||||
|
||||
private static final String FEATURE_SECURE_PROCESSING = "http://javax.xml.XMLConstants/feature/secure-processing";
|
||||
|
||||
private static Processor processor;
|
||||
|
||||
static {
|
||||
try {
|
||||
Class.forName(ORACLE_XERCES_CLASS);
|
||||
} catch (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");
|
||||
}
|
||||
}
|
||||
|
||||
private ObjectFactory() {
|
||||
// hide, it's a factory
|
||||
}
|
||||
|
||||
private static DocumentBuilderFactory createDocumentBuilderFactory(boolean validating) {
|
||||
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
||||
try {
|
||||
dbf.setValidating(validating);
|
||||
dbf.setNamespaceAware(true);
|
||||
|
||||
// explicitly enable secure processing
|
||||
dbf.setFeature(FEATURE_SECURE_PROCESSING, true);
|
||||
|
||||
// This is the PRIMARY defense. If DTDs (doctypes) are disallowed, almost all XML entity attacks are prevented
|
||||
dbf.setFeature(DISSALLOW_DOCTYPE_DECL_FEATURE, true);
|
||||
|
||||
// Disable external DTDs as well
|
||||
dbf.setFeature(LOAD_EXTERNAL_DTD_FEATURE, false);
|
||||
|
||||
// and these as well, per Timothy Morgan's 2014 paper: "XML Schema, DTD, and Entity Attacks"
|
||||
dbf.setXIncludeAware(false);
|
||||
dbf.setExpandEntityReferences(false);
|
||||
return dbf;
|
||||
} catch (ParserConfigurationException e) {
|
||||
throw new IllegalStateException("Can not create DocumentBuilderFactory due to underlying configuration error", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Transformer für die Ausgabe. Nutzt nicht Saxon!
|
||||
*
|
||||
* @param prettyPrint pretty-printing der Ausgabe
|
||||
* @return einen vorkonfigurierten Transformer
|
||||
*/
|
||||
public static Transformer createTransformer(boolean prettyPrint) {
|
||||
Transformer transformer = null;
|
||||
try {
|
||||
transformer = TransformerFactory.newInstance().newTransformer();
|
||||
if (prettyPrint) {
|
||||
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
|
||||
transformer.setOutputProperty(OutputKeys.METHOD, "xml");
|
||||
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
|
||||
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
|
||||
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
|
||||
}
|
||||
return transformer;
|
||||
} catch (TransformerConfigurationException e) {
|
||||
throw new IllegalStateException("Can not create Transformer due to underlying configuration error", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Erzeugt einen Zeitstempel zur Verwendung in XML-Objekten
|
||||
*
|
||||
* @return eine Instanz {@link XMLGregorianCalendar}
|
||||
*/
|
||||
public static XMLGregorianCalendar createTimestamp() {
|
||||
try {
|
||||
GregorianCalendar cal = new GregorianCalendar();
|
||||
cal.setTime(new Date());
|
||||
return DatatypeFactory.newInstance().newXMLGregorianCalendar(cal);
|
||||
|
||||
} catch (DatatypeConfigurationException e) {
|
||||
throw new IllegalStateException("Can not create timestamp", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static DocumentBuilder createDocumentBuilder(boolean validating) {
|
||||
try {
|
||||
return createDocumentBuilderFactory(validating).newDocumentBuilder();
|
||||
} catch (ParserConfigurationException e) {
|
||||
throw new IllegalStateException("Can not create DocumentFactory due to underlying configuration error", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static String encode(String input) {
|
||||
try {
|
||||
return URLEncoder.encode(input, StandardCharsets.UTF_8.name());
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new IllegalStateException("Error encoding property while initializing saxon", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static Processor createProcessor() {
|
||||
if (processor == null) {
|
||||
processor = new Processor(false);
|
||||
//verhindere global im Prinzip alle resolving strategien
|
||||
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
|
||||
|
||||
//grundsätzlich Feature-konfiguration:
|
||||
processor.setConfigurationProperty(FeatureKeys.DTD_VALIDATION, false);
|
||||
processor.setConfigurationProperty(FeatureKeys.ENTITY_RESOLVER_CLASS, "");
|
||||
processor.setConfigurationProperty(FeatureKeys.XINCLUDE, false);
|
||||
processor.setConfigurationProperty(FeatureKeys.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), false);
|
||||
processor.setConfigurationProperty(FeatureKeys.XML_PARSER_FEATURE + encode(LOAD_EXTERNAL_DTD_FEATURE), false);
|
||||
}
|
||||
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(Schema schema) {
|
||||
final Validator validator = schema.newValidator();
|
||||
try {
|
||||
validator.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");
|
||||
} catch (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 (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() {
|
||||
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 (SAXException e) {
|
||||
log.warn("Can not disable external DTD access, maybe an unsupported JAXP implementation is used", e);
|
||||
}
|
||||
return sf;
|
||||
}
|
||||
|
||||
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(String href, String base) throws TransformerException {
|
||||
throw new IllegalStateException(MESSAGE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close(Result result) throws TransformerException {
|
||||
throw new IllegalStateException(MESSAGE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Reader resolve(URI absoluteURI, String encoding, Configuration config) throws XPathException {
|
||||
throw new IllegalStateException(MESSAGE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceCollection findCollection(XPathContext context, String collectionURI) throws XPathException {
|
||||
throw new IllegalStateException(MESSAGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,85 +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;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.net.URI;
|
||||
|
||||
import javax.xml.transform.Source;
|
||||
import javax.xml.transform.TransformerException;
|
||||
import javax.xml.transform.URIResolver;
|
||||
import javax.xml.transform.stream.StreamSource;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import net.sf.saxon.Configuration;
|
||||
import net.sf.saxon.lib.UnparsedTextURIResolver;
|
||||
import net.sf.saxon.trans.XPathException;
|
||||
|
||||
/**
|
||||
* {@link URIResolver} that resolves artifacts relative to a given base uri. The resolved URI must be resolving as child
|
||||
* e.g. the baseUri must be a parent of the resolved artifact.
|
||||
*
|
||||
* @author Andreas Penski
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class RelativeUriResolver implements URIResolver, UnparsedTextURIResolver {
|
||||
|
||||
/** the base uri */
|
||||
private final URI baseUri;
|
||||
|
||||
@Override
|
||||
public Source resolve(final String href, final String base) throws TransformerException {
|
||||
final URI resolved = URI.create(base).resolve(href);
|
||||
if (isUnderBaseUri(resolved)) {
|
||||
try {
|
||||
return new StreamSource(resolved.toURL().openStream());
|
||||
} catch (final IOException e) {
|
||||
|
||||
throw new IllegalStateException(String.format("Can not resolve required %s", href), e);
|
||||
}
|
||||
} else {
|
||||
throw new IllegalStateException(
|
||||
String.format("The resolved transformation artifact %s is not within the configured repository %s", resolved, baseUri));
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isUnderBaseUri(URI resolved) {
|
||||
String base = baseUri.toASCIIString().replaceAll("file:/+", "");
|
||||
String r = resolved.toASCIIString().replaceAll("file:/+", "");
|
||||
return r.startsWith(base);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Reader resolve(URI absoluteURI, String encoding, Configuration config) throws XPathException {
|
||||
if (isUnderBaseUri(absoluteURI)) {
|
||||
try {
|
||||
return new InputStreamReader(absoluteURI.toURL().openStream(), encoding);
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException(String.format("Can not resolve required %s", absoluteURI), e);
|
||||
}
|
||||
} else {
|
||||
throw new IllegalStateException(
|
||||
String.format("The resolved transformation artifact %s is not within the configured repository %s", absoluteURI, baseUri));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,173 +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;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.xml.transform.dom.DOMSource;
|
||||
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import de.kosit.validationtool.api.CheckConfiguration;
|
||||
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 de.kosit.validationtool.model.scenarios.ScenarioType;
|
||||
import de.kosit.validationtool.model.scenarios.Scenarios;
|
||||
|
||||
import net.sf.saxon.s9api.*;
|
||||
|
||||
/**
|
||||
* Repository for die aktiven Szenario einer Prüfinstanz.
|
||||
*
|
||||
* @author Andreas Penski
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class ScenarioRepository {
|
||||
|
||||
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";
|
||||
|
||||
@Getter(value = AccessLevel.PRIVATE)
|
||||
|
||||
private final Processor processor;
|
||||
|
||||
@Getter(value = AccessLevel.PRIVATE)
|
||||
private final ContentRepository repository;
|
||||
|
||||
private XsltExecutable noScenarioReport;
|
||||
|
||||
@Getter(value = AccessLevel.PACKAGE)
|
||||
private Scenarios scenarios;
|
||||
|
||||
private static boolean isSupportedDocument(Document doc) {
|
||||
final Element root = doc.getDocumentElement();
|
||||
return root.hasAttribute("frameworkVersion") && root.getAttribute("frameworkVersion").startsWith(SUPPORTED_MAJOR_VERSION)
|
||||
&& doc.getDocumentElement().getNamespaceURI().equals(SUPPORTED_MAJOR_VERSION_SCHEMA);
|
||||
}
|
||||
|
||||
private static void checkVersion(URI scenarioDefinition) {
|
||||
DocumentParseAction p = new DocumentParseAction();
|
||||
try {
|
||||
final Result<Document, XMLSyntaxError> result = p.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 (MalformedURLException e) {
|
||||
throw new IllegalStateException("Error reading definition file");
|
||||
}
|
||||
}
|
||||
|
||||
public XsltExecutable getNoScenarioReport() {
|
||||
if (noScenarioReport == null) {
|
||||
noScenarioReport = repository.loadXsltScript(URI.create(scenarios.getNoScenarioReport().getResource().getLocation()));
|
||||
}
|
||||
return noScenarioReport;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialisiert das Repository mit der angegebenen Konfiguration.
|
||||
*
|
||||
* @param config die Konfiguration
|
||||
*/
|
||||
public void initialize(CheckConfiguration config) {
|
||||
ConversionService conversionService = new ConversionService();
|
||||
checkVersion(config.getScenarioDefinition());
|
||||
log.info("Loading scenarios from {}", config.getScenarioDefinition());
|
||||
CollectingErrorEventHandler handler = new CollectingErrorEventHandler();
|
||||
this.scenarios = conversionService.readXml(config.getScenarioDefinition(), Scenarios.class, repository.getScenarioSchema(),
|
||||
handler);
|
||||
if (!handler.hasErrors()) {
|
||||
log.info("Loaded scenarios for {} by {} from {}. The following scenarios are available:\n\n{}", scenarios.getName(),
|
||||
scenarios.getAuthor(), scenarios.getDate(), summarizeScenarios());
|
||||
log.info("Loading scenario content from {}", config.getScenarioRepository());
|
||||
getScenarios().getScenario().forEach(s -> s.initialize(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
|
||||
getNoScenarioReport();
|
||||
|
||||
}
|
||||
|
||||
private String summarizeScenarios() {
|
||||
StringBuilder b = new StringBuilder();
|
||||
scenarios.getScenario().forEach(s -> {
|
||||
b.append(s.getName());
|
||||
b.append("\n");
|
||||
});
|
||||
return b.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Ermittelt für das angegebene Dokument das passende Szenario.
|
||||
*
|
||||
* @param document das Eingabedokument
|
||||
* @return ein Ergebnis-Objekt zur weiteren Verarbeitung
|
||||
*/
|
||||
public Result<ScenarioType, String> selectScenario(Document document) {
|
||||
Result<ScenarioType, String> result = new Result<>();
|
||||
final List<ScenarioType> collect = scenarios.getScenario().stream().filter(s -> match(document, s)).collect(Collectors.toList());
|
||||
if (collect.size() == 1) {
|
||||
result = new Result<>(collect.get(0));
|
||||
} else if (collect.isEmpty()) {
|
||||
result.getErrors().add("None of the loaded scenarios matches the specified document");
|
||||
} else {
|
||||
result.getErrors().add("More than on scenario matches the specified document");
|
||||
}
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
private boolean match(Document document, ScenarioType scenario) {
|
||||
try {
|
||||
final XPathSelector selector = scenario.getSelector();
|
||||
DocumentBuilder documentBuilder = getProcessor().newDocumentBuilder();
|
||||
|
||||
final XdmNode xdmSource = documentBuilder.build(new DOMSource(document));
|
||||
selector.setContextItem(xdmSource);
|
||||
return selector.effectiveBooleanValue();
|
||||
} catch (SaxonApiException e) {
|
||||
log.error("Error evaluating xpath expression", e);
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
void initialize(Scenarios def) {
|
||||
this.scenarios = def;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,187 +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.validation.Schema;
|
||||
|
||||
import org.apache.commons.lang3.NotImplementedException;
|
||||
import org.w3c.dom.Document;
|
||||
|
||||
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.*;
|
||||
|
||||
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
|
||||
*/
|
||||
public abstract class BaseScenario {
|
||||
|
||||
private XPathExecutable xPathExecutable;
|
||||
|
||||
private Schema schema;
|
||||
|
||||
private List<Transformation> schematronValidations;
|
||||
|
||||
private ContentRepository repository;
|
||||
|
||||
private Transformation reportTransformation;
|
||||
|
||||
/**
|
||||
* Gibt eine Transformation zurück.
|
||||
* @return initialisierte Transformation
|
||||
*/
|
||||
public Transformation getReportTransformation() {
|
||||
if (reportTransformation == null) {
|
||||
final ResourceType resource = getCreateReport().getResource();
|
||||
final XsltExecutable executable = repository.loadXsltScript(URI.create(resource.getLocation()));
|
||||
reportTransformation = new Transformation(executable, resource);
|
||||
}
|
||||
return reportTransformation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lieferrt das Schema zu diesem Szenario.
|
||||
* @return das passende Schema
|
||||
*/
|
||||
public Schema getSchema() {
|
||||
if (schema == null) {
|
||||
final List<String> schemaResources = getValidateWithXmlSchema().getResource().stream().map(r -> r.getLocation())
|
||||
.collect(Collectors.toList());
|
||||
schema = repository.createSchema(schemaResources);
|
||||
}
|
||||
return schema;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initialisiert das Szenario auf Basis eines [@link ContentRepository}
|
||||
* @param repository das Repository mit den Szenario-Artefakten
|
||||
* @param lazy optionales lazy loading der XML-Artefakte
|
||||
* @return true wenn erfolgreich
|
||||
*/
|
||||
public boolean initialize(ContentRepository repository, boolean lazy) {
|
||||
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 (schematronValidations == null) {
|
||||
schematronValidations = new ArrayList<>();
|
||||
getValidateWithSchematron().forEach(v -> {
|
||||
if (v.isPsvi()) {
|
||||
throw new NotImplementedException("This implemenation does not support PSVI usage");
|
||||
}
|
||||
final XsltExecutable xsltExecutable = repository.loadXsltScript(URI.create(v.getResource().getLocation()));
|
||||
schematronValidations.add(new Transformation(xsltExecutable, v.getResource()));
|
||||
});
|
||||
}
|
||||
return schematronValidations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Der XPath-Selector zur Identifikation des Scenarios.
|
||||
*
|
||||
* @return vorbereiteten selector
|
||||
* @see {@link ScenarioRepository#selectScenario(Document)}.
|
||||
*/
|
||||
public XPathSelector getSelector() {
|
||||
if (xPathExecutable == null) {
|
||||
final Map<String, String> namespaces = getNamespace().stream().collect(Collectors.toMap(NamespaceType::getPrefix, NamespaceType::getValue));
|
||||
xPathExecutable = repository.createXPath(getMatch(), namespaces);
|
||||
}
|
||||
return xPathExecutable.load();
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter aus dem schema.
|
||||
*
|
||||
* @return xpath match
|
||||
*/
|
||||
public abstract String getMatch();
|
||||
|
||||
/**
|
||||
* 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();
|
||||
|
||||
/**
|
||||
* Laufzeitinformationen über eine Transformation.
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@AllArgsConstructor
|
||||
public class Transformation {
|
||||
|
||||
private XsltExecutable executable;
|
||||
|
||||
private ResourceType resourceType;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,82 +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 org.slf4j.Logger;
|
||||
|
||||
import de.kosit.validationtool.model.reportInput.XMLSyntaxErrorSeverity;
|
||||
|
||||
/**
|
||||
* Basis-Klasse für Syntax-Error. Wird über die JAXB-generierte Klasse
|
||||
* {@link de.kosit.validationtool.model.reportInput.XMLSyntaxError} erweitert.
|
||||
*
|
||||
* @author Andreas Penski
|
||||
*/
|
||||
public abstract class BaseXMLSyntaxError {
|
||||
|
||||
/**
|
||||
* Logged den Syntax-Fehler über einen definierten Logger.
|
||||
*
|
||||
* @param logger der Logger
|
||||
*/
|
||||
public void log(Logger logger) {
|
||||
String msgTemplate = "{} At row {} at pos {}";
|
||||
Object[] params = { getMessage(), getRowNumber(), getColumnNumber() };
|
||||
if (getSeverity() == XMLSyntaxErrorSeverity.SEVERITY_WARNING) {
|
||||
logger.warn(msgTemplate, params);
|
||||
} else {
|
||||
logger.error(msgTemplate, params);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("%s At row %s at pos %s", getMessage(), getRowNumber(), getColumnNumber());
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter aus dem schema
|
||||
*
|
||||
* @return Spalte des Fehlers
|
||||
*/
|
||||
public abstract Integer getColumnNumber();
|
||||
|
||||
/**
|
||||
* Getter aus dem schema
|
||||
*
|
||||
* @return Zeile des Fehlers
|
||||
*/
|
||||
public abstract Integer getRowNumber();
|
||||
|
||||
/**
|
||||
* Getter aus dem schema
|
||||
*
|
||||
* @return Fehlermeldung
|
||||
*/
|
||||
public abstract String getMessage();
|
||||
|
||||
/**
|
||||
* Getter aus dem schema
|
||||
*
|
||||
* @return severity
|
||||
*/
|
||||
public abstract XMLSyntaxErrorSeverity getSeverity();
|
||||
}
|
||||
|
|
@ -1,80 +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.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* Ein Ergebnisobjekte, dass das eigentliche Ergebnis hält und optional auch verschiedene Fehlerobjekte.
|
||||
*
|
||||
* @param <T> der Typ des Ergebnis-Objekts
|
||||
* @param <E> der Typ des Fehler-Objekts
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class Result<T, E> {
|
||||
|
||||
private T object;
|
||||
|
||||
private Collection<E> errors = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Erzeugt ein neues Ergebnis mit Fehler
|
||||
*
|
||||
* @param errors die Fehler
|
||||
*/
|
||||
public Result(Collection<E> errors) {
|
||||
this(null, errors);
|
||||
}
|
||||
|
||||
/**
|
||||
* Erzeugt ein neues Ergebnis mit einem Ergebnisobjekt
|
||||
*
|
||||
* @param o
|
||||
*/
|
||||
public Result(T o) {
|
||||
this(o, Collections.emptyList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Zeigt an, ob das Ergebnis valide, also ohne Fehler ist.
|
||||
*
|
||||
* @return true wenn erfolgreich
|
||||
*/
|
||||
public boolean isValid() {
|
||||
return object != null && errors.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Zeigt an, ob das Ergebnis nicht valide ist, als entsprechend Fehler gesammelt wurden.
|
||||
*
|
||||
* @return true wenn erfolgreich wenn Fehler vorhanden sind.
|
||||
*/
|
||||
public boolean isInvalid() {
|
||||
return !isValid();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,120 +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.tasks;
|
||||
|
||||
import de.kosit.validationtool.api.Input;
|
||||
import de.kosit.validationtool.impl.model.Result;
|
||||
import de.kosit.validationtool.model.reportInput.CreateReportInput;
|
||||
import de.kosit.validationtool.model.reportInput.XMLSyntaxError;
|
||||
import de.kosit.validationtool.model.scenarios.ScenarioType;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.w3c.dom.Document;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Interface, welches von allen Prüfschritten implementiert wird. Der Parameter vom Typ {@link Bag} dient dabei sowohl
|
||||
* als Quellce für Eingabe Parameter als auch für die Aufnahme von Ergebnisse, die an weitere Schritte weitergeleitet
|
||||
* werden sollen.
|
||||
*
|
||||
* @author Andreas Penski
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface CheckAction {
|
||||
|
||||
/**
|
||||
* Ausfürhung des Prüfschrittes und Erweiterung der gesammelten Informationen.
|
||||
*
|
||||
* @param results die Informationssammlung
|
||||
*/
|
||||
void check(Bag results);
|
||||
|
||||
/**
|
||||
* Ermittlung, ob ein Schritt u.U. ausgelassen werden kann. Die Funktion wird vor der eigentlichen Prüfaktion aufgerufen
|
||||
* und kann somit eine Ausführung des Prüfschrittes verhindern. Entwickler können diese Funktion überschreiben, um den
|
||||
* Prüfschritt bedingt auszuführen.
|
||||
*
|
||||
* @param results die bisher gesammelten Information
|
||||
* @return <tt>true</tt> wenn der Schritt ausgelassen werden soll
|
||||
*/
|
||||
default boolean isSkipped(Bag results) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transport-Klasse für Eingabe und Ausgabe-Objekte für die einzelnen Prüfschritte.
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
class Bag {
|
||||
|
||||
private Result<ScenarioType, String> scenarioSelectionResult;
|
||||
|
||||
private CreateReportInput reportInput;
|
||||
|
||||
/** Das finale Ergebnis */
|
||||
private Document report;
|
||||
|
||||
private boolean finished;
|
||||
|
||||
private boolean stopped;
|
||||
|
||||
/** Das zu prüfende Dokument */
|
||||
private Input input;
|
||||
|
||||
private Result<Document, XMLSyntaxError> parserResult;
|
||||
|
||||
private Result<Integer, String> assertionResult;
|
||||
|
||||
private Result<Boolean, XMLSyntaxError> schemaValidationResult;
|
||||
|
||||
public Bag(Input input) {
|
||||
this(input, new CreateReportInput());
|
||||
}
|
||||
|
||||
public Bag(Input input, CreateReportInput reportInput) {
|
||||
this.input = input;
|
||||
this.reportInput = reportInput;
|
||||
}
|
||||
|
||||
/**
|
||||
* Signalisiert einen vorzeitigen Stop der Vearbeitung.
|
||||
*/
|
||||
public void stopProcessing() {
|
||||
this.stopped = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt den Namen des Prüflings zurück, dabei werden etwaige Pfadinformationen abgeschnitten.
|
||||
*
|
||||
* @return der Name des Prüflings
|
||||
*/
|
||||
public String getName() {
|
||||
final String fileName = getInput().getName().replaceAll(".*/|.*\\\\", "");
|
||||
final Matcher matcher = Pattern.compile("(.*)\\..+").matcher(fileName);
|
||||
if (matcher.matches()) {
|
||||
return matcher.group(1);
|
||||
}
|
||||
return fileName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,94 +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.tasks;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import javax.xml.transform.dom.DOMSource;
|
||||
|
||||
import org.w3c.dom.Document;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import de.kosit.validationtool.impl.*;
|
||||
import de.kosit.validationtool.impl.model.Result;
|
||||
import de.kosit.validationtool.model.scenarios.ScenarioType;
|
||||
|
||||
import net.sf.saxon.s9api.*;
|
||||
|
||||
/**
|
||||
* Erzeugt den Report auf Basis der gesammelten Informationen über den Prüfling. Sollte kein Szenario identifiziert
|
||||
* worden sein, so wird ein {@link ScenarioRepository#getNoScenarioReport() default report} erzeugt.
|
||||
*
|
||||
* @author Andreas Penski
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class CreateReportAction implements CheckAction {
|
||||
|
||||
private final Processor processor;
|
||||
|
||||
private final ConversionService conversionService;
|
||||
|
||||
private final ScenarioRepository repository;
|
||||
|
||||
private final URI contentRepository;
|
||||
|
||||
private static XsltExecutable loadFromScenario(ScenarioType object) {
|
||||
return object.getReportTransformation().getExecutable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void check(Bag results) {
|
||||
final DocumentBuilder documentBuilder = processor.newDocumentBuilder();
|
||||
try {
|
||||
|
||||
final Document inputDoc = results.getParserResult().isValid() ? results.getParserResult().getObject()
|
||||
: ObjectFactory.createDocumentBuilder(true).newDocument();
|
||||
|
||||
final XdmNode parsedDocument = documentBuilder.build(new DOMSource(inputDoc));
|
||||
final Document reportInput = conversionService.writeDocument(results.getReportInput());
|
||||
final XdmNode root = documentBuilder.build(new DOMSource(reportInput));
|
||||
final XsltTransformer transformer = getTransformation(results).load();
|
||||
transformer.setInitialContextNode(root);
|
||||
CollectingErrorEventHandler e = new CollectingErrorEventHandler();
|
||||
RelativeUriResolver resolver = new RelativeUriResolver(contentRepository);
|
||||
transformer.setMessageListener(e);
|
||||
transformer.setURIResolver(resolver);
|
||||
transformer.getUnderlyingController().setUnparsedTextURIResolver(resolver);
|
||||
transformer.setParameter(new QName("input-document"), parsedDocument);
|
||||
Document result = ObjectFactory.createDocumentBuilder(false).newDocument();
|
||||
transformer.setDestination(new DOMDestination(result));
|
||||
transformer.transform();
|
||||
results.setReport(result);
|
||||
|
||||
} catch (SaxonApiException e) {
|
||||
throw new IllegalStateException("Can not create final report", e);
|
||||
}
|
||||
}
|
||||
|
||||
private XsltExecutable getTransformation(Bag results) {
|
||||
final Result<ScenarioType, String> scenario = results.getScenarioSelectionResult();
|
||||
return scenario != null && scenario.isValid() ? loadFromScenario(scenario.getObject()) : loadFallback();
|
||||
}
|
||||
|
||||
private XsltExecutable loadFallback() {
|
||||
return repository.getNoScenarioReport();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,90 +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.tasks;
|
||||
|
||||
import de.kosit.validationtool.api.Input;
|
||||
import de.kosit.validationtool.impl.CollectingErrorEventHandler;
|
||||
import de.kosit.validationtool.impl.ObjectFactory;
|
||||
import de.kosit.validationtool.impl.model.Result;
|
||||
import de.kosit.validationtool.model.reportInput.ValidationResultsWellformedness;
|
||||
import de.kosit.validationtool.model.reportInput.XMLSyntaxError;
|
||||
import de.kosit.validationtool.model.reportInput.XMLSyntaxErrorSeverity;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.w3c.dom.Document;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* Setzt Parsing-Funktionalitäten um. Prüft auf well-formedness
|
||||
*
|
||||
* @author Andreas Penski
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class DocumentParseAction implements CheckAction {
|
||||
|
||||
/**
|
||||
* 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 das Validierung gegenüber ein Schema.
|
||||
*
|
||||
* @param content ein Dokument
|
||||
* @return Ergebnis des Parsings inklusive etwaiger Fehler
|
||||
*/
|
||||
public Result<Document, XMLSyntaxError> parseDocument(Input content) {
|
||||
if (content == null) {
|
||||
throw new IllegalArgumentException("Url may not be null");
|
||||
}
|
||||
Result<Document, XMLSyntaxError> result;
|
||||
CollectingErrorEventHandler errorHandler = new CollectingErrorEventHandler();
|
||||
try ( InputStream input = new ByteArrayInputStream(content.getContent()) ) {
|
||||
DocumentBuilder db = ObjectFactory.createDocumentBuilder(false);
|
||||
db.setErrorHandler(errorHandler);
|
||||
Document doc = db.parse(input);
|
||||
result = new Result<>(doc, errorHandler.getErrors());
|
||||
} catch (SAXException e) {
|
||||
log.debug("SAXException while parsing {}", content.getName(), e);
|
||||
result = new Result<>(errorHandler.getErrors());
|
||||
} catch (IOException e) {
|
||||
log.debug("IOException while parsing {}", content, e);
|
||||
XMLSyntaxError error = new XMLSyntaxError();
|
||||
error.setSeverity(XMLSyntaxErrorSeverity.SEVERITY_FATAL_ERROR);
|
||||
error.setMessage(String.format("IOException while reading resource %s", content.getName()));
|
||||
result = new Result<>(Collections.singleton(error));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void check(Bag results) {
|
||||
Result<Document, XMLSyntaxError> parserResult = parseDocument(results.getInput());
|
||||
ValidationResultsWellformedness v = new ValidationResultsWellformedness();
|
||||
results.setParserResult(parserResult);
|
||||
v.getXmlSyntaxError().addAll(parserResult.getErrors());
|
||||
results.getReportInput().setValidationResultsWellformedness(v);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,60 +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.tasks;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
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.reportInput.ProcessingError;
|
||||
import de.kosit.validationtool.model.scenarios.ScenarioType;
|
||||
|
||||
/**
|
||||
* Identifiziert das der Eingabe entsprechende Szenario, sofern eines konfiguriert ist.
|
||||
*
|
||||
* @author Andreas Penski
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class ScenarioSelectionAction implements CheckAction {
|
||||
|
||||
private final ScenarioRepository repository;
|
||||
|
||||
@Override
|
||||
public void check(Bag results) {
|
||||
final CreateReportInput report = results.getReportInput();
|
||||
final Result<ScenarioType, String> scenarioTypeResult = repository.selectScenario(results.getParserResult().getObject());
|
||||
results.setScenarioSelectionResult(scenarioTypeResult);
|
||||
if (scenarioTypeResult.isValid()) {
|
||||
final ScenarioType scenario = scenarioTypeResult.getObject();
|
||||
report.setScenario(scenario);
|
||||
} else {
|
||||
if (report.getProcessingError() == null) {
|
||||
report.setProcessingError(new ProcessingError());
|
||||
}
|
||||
report.getProcessingError().getError().addAll(scenarioTypeResult.getErrors());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSkipped(Bag results) {
|
||||
return results.getParserResult().isInvalid();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,86 +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.tasks;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import javax.xml.transform.stream.StreamSource;
|
||||
import javax.xml.validation.Validator;
|
||||
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import de.kosit.validationtool.impl.CollectingErrorEventHandler;
|
||||
import de.kosit.validationtool.impl.ObjectFactory;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Schema-Validierung der Eingabe-Datei mittels Schema-Definition aus dem identifizierten Szenario.
|
||||
*
|
||||
* @author Andreas Penski
|
||||
*/
|
||||
@Slf4j
|
||||
public class SchemaValidationAction implements CheckAction {
|
||||
|
||||
private Result<Boolean, XMLSyntaxError> validate(byte[] document, ScenarioType scenarioType) {
|
||||
log.debug("Validating document using scenario {}", scenarioType.getName());
|
||||
final CollectingErrorEventHandler errorHandler = new CollectingErrorEventHandler();
|
||||
try ( InputStream input = new ByteArrayInputStream(document) ) {
|
||||
final Validator validator = ObjectFactory.createValidator(scenarioType.getSchema());
|
||||
validator.setErrorHandler(errorHandler);
|
||||
validator.validate(new StreamSource(input));
|
||||
return new Result<>(!errorHandler.hasErrors(), errorHandler.getErrors());
|
||||
} catch (SAXException | IOException e) {
|
||||
throw new IllegalStateException("Error validating document", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void check(Bag results) {
|
||||
final CreateReportInput report = results.getReportInput();
|
||||
final ScenarioType scenario = results.getScenarioSelectionResult().getObject();
|
||||
final Result<Boolean, XMLSyntaxError> validateResult = validate(results.getInput().getContent(), scenario);
|
||||
results.setSchemaValidationResult(validateResult);
|
||||
ValidationResultsXmlSchema result = new ValidationResultsXmlSchema();
|
||||
report.setValidationResultsXmlSchema(result);
|
||||
result.getResource().addAll(scenario.getValidateWithXmlSchema().getResource());
|
||||
if (!validateResult.isValid()) {
|
||||
result.getXmlSyntaxError().addAll(validateResult.getErrors());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isSkipped(Bag results) {
|
||||
return hasNoScenario(results);
|
||||
}
|
||||
|
||||
private static boolean hasNoScenario(Bag results) {
|
||||
return results.getScenarioSelectionResult() == null || results.getScenarioSelectionResult().isInvalid();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,97 +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.tasks;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.xml.transform.dom.DOMSource;
|
||||
|
||||
import org.w3c.dom.Document;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import de.kosit.validationtool.impl.CollectingErrorEventHandler;
|
||||
import de.kosit.validationtool.impl.ObjectFactory;
|
||||
import de.kosit.validationtool.impl.RelativeUriResolver;
|
||||
import de.kosit.validationtool.impl.model.BaseScenario;
|
||||
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.*;
|
||||
|
||||
/**
|
||||
* Ausführung von konfigurierten Schematron Validierungen eines Szenarios.
|
||||
*
|
||||
* @author Andreas Penski
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class SchematronValidationAction implements CheckAction {
|
||||
|
||||
private final Processor processor;
|
||||
|
||||
private final URI repository;
|
||||
|
||||
private List<ValidationResultsSchematron> validate(Document document, ScenarioType scenario) {
|
||||
return scenario.getSchematronValidations().stream().map(v -> validate(document, v)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private ValidationResultsSchematron validate(Document document, BaseScenario.Transformation validation) {
|
||||
final DocumentBuilder documentBuilder = processor.newDocumentBuilder();
|
||||
try {
|
||||
final XdmNode root = documentBuilder.build(new DOMSource(document));
|
||||
final XsltTransformer transformer = validation.getExecutable().load();
|
||||
//resolving nur relative zum Repository
|
||||
final RelativeUriResolver resolver = new RelativeUriResolver(repository);
|
||||
transformer.setURIResolver(resolver);
|
||||
CollectingErrorEventHandler e = new CollectingErrorEventHandler();
|
||||
transformer.setMessageListener(e);
|
||||
|
||||
Document result = ObjectFactory.createDocumentBuilder(false).newDocument();
|
||||
transformer.setDestination(new DOMDestination(result));
|
||||
transformer.setInitialContextNode(root);
|
||||
transformer.transform();
|
||||
ValidationResultsSchematron s = new ValidationResultsSchematron();
|
||||
s.setResource(validation.getResourceType());
|
||||
ValidationResultsSchematron.Results r = new ValidationResultsSchematron.Results();
|
||||
r.setAny(result.getDocumentElement());
|
||||
s.setResults(r);
|
||||
return s;
|
||||
|
||||
} catch (SaxonApiException e) {
|
||||
throw new IllegalStateException("Can not run schematron validation", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void check(Bag results) {
|
||||
final CreateReportInput report = results.getReportInput();
|
||||
final List<ValidationResultsSchematron> bla = validate(results.getParserResult().getObject(),
|
||||
results.getScenarioSelectionResult().getObject());
|
||||
report.getValidationResultsSchematron().addAll(bla);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSkipped(Bag results) {
|
||||
return results.getSchemaValidationResult() == null || results.getSchemaValidationResult().isInvalid();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,68 +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.tasks;
|
||||
|
||||
import javax.xml.validation.Schema;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import de.kosit.validationtool.impl.CollectingErrorEventHandler;
|
||||
import de.kosit.validationtool.impl.ConversionService;
|
||||
import de.kosit.validationtool.impl.model.Result;
|
||||
import de.kosit.validationtool.model.reportInput.XMLSyntaxError;
|
||||
|
||||
/**
|
||||
* Validiert die gesammelten Informationen über den Prüfling. Zusätzlich Check.
|
||||
*
|
||||
* @author Andreas Penski
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class ValidateReportInputAction implements CheckAction {
|
||||
|
||||
private final ConversionService conversionService;
|
||||
|
||||
private final Schema schema;
|
||||
|
||||
@Override
|
||||
public void check(Bag bag) {
|
||||
final Result<Boolean, XMLSyntaxError> results = validate(bag.getReportInput());
|
||||
if (!results.isValid()) {
|
||||
log.error("Report input has errors {}", results.getErrors());
|
||||
bag.stopProcessing();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validatiert das gegebene JAXB-Objekt gegen das konfigurierte Schema
|
||||
*
|
||||
* @param object das JAXB-Objekt
|
||||
* @param <T> der Typ des Objekts
|
||||
* @return ein Validierungsergebnis
|
||||
*/
|
||||
private <T> Result<Boolean, XMLSyntaxError> validate(T object) {
|
||||
CollectingErrorEventHandler h = new CollectingErrorEventHandler();
|
||||
final String result = conversionService.writeXml(object, schema, h);
|
||||
return new Result<>(StringUtils.isNotBlank(result), h.getErrors());
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue