Verzeichnisstruktur erweitert, um Prüftool und Konfiguration XRechnung aufzunehmen.

This commit is contained in:
fbuettner 2017-10-26 10:24:07 +02:00
parent 0fd87014b4
commit 4eab984c01
161 changed files with 106853 additions and 11 deletions

View file

@ -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;
}
}
}

View file

@ -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();
}
}

View file

@ -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);
}
}
}

View file

@ -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);
}
}
}

View file

@ -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;
}
}

View file

@ -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);
}
}
}

View file

@ -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));
}
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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();
}

View file

@ -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();
}
}

View file

@ -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;
}
}
}

View file

@ -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();
}
}

View file

@ -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);
}
}

View file

@ -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();
}
}

View file

@ -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();
}
}

View file

@ -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();
}
}

View file

@ -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());
}
}