mirror of
https://github.com/itplr-kosit/validator.git
synced 2026-05-26 01:05:38 +00:00
support multiple configuration
This commit is contained in:
parent
730d7fefe9
commit
2e6efdd16f
59 changed files with 1136 additions and 608 deletions
|
|
@ -34,7 +34,6 @@ 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;
|
||||
|
|
@ -67,8 +66,6 @@ import net.sf.saxon.s9api.XsltExecutable;
|
|||
@Slf4j
|
||||
public class ContentRepository {
|
||||
|
||||
private Schema reportInputSchema;
|
||||
|
||||
@Getter
|
||||
private final Processor processor;
|
||||
|
||||
|
|
@ -90,10 +87,10 @@ public class ContentRepository {
|
|||
* @param strategy the security and resolving strategy
|
||||
* @param repository the repository.
|
||||
*/
|
||||
public ContentRepository(final ResolvingConfigurationStrategy strategy, final URI repository) {
|
||||
public ContentRepository(final Processor processor, final ResolvingConfigurationStrategy strategy, final URI repository) {
|
||||
this.repository = repository;
|
||||
this.resolvingConfigurationStrategy = strategy;
|
||||
this.processor = this.resolvingConfigurationStrategy.getProcessor();
|
||||
this.processor = processor;
|
||||
this.resolver = this.resolvingConfigurationStrategy.createResolver(repository);
|
||||
this.unparsedTextURIResolver = this.resolvingConfigurationStrategy.createUnparsedTextURIResolver(repository);
|
||||
this.schemaFactory = this.resolvingConfigurationStrategy.createSchemaFactory();
|
||||
|
|
@ -108,20 +105,15 @@ public class ContentRepository {
|
|||
}
|
||||
}
|
||||
|
||||
private Schema createSchema(final Source[] schemaSources, final LSResourceResolver resourceResolver) {
|
||||
private Schema createSchema(final Source[] schemaSources) {
|
||||
try {
|
||||
final SchemaFactory sf = this.schemaFactory;
|
||||
sf.setResourceResolver(resourceResolver);
|
||||
return sf.newSchema(schemaSources);
|
||||
this.schemaFactory.setResourceResolver(null);
|
||||
return this.schemaFactory.newSchema(schemaSources);
|
||||
} catch (final SAXException e) {
|
||||
throw new IllegalArgumentException("Can not load schema from sources " + schemaSources[0].getSystemId(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private Schema createSchema(final Source[] schemaSources) {
|
||||
return createSchema(schemaSources, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Lädt ein XSL von der angegebenen URI
|
||||
*
|
||||
|
|
@ -158,40 +150,13 @@ public class ContentRepository {
|
|||
* @return das erzeugte Schema
|
||||
*/
|
||||
public Schema createSchema(final URL url) {
|
||||
return createSchema(url, null);
|
||||
return createSchema(new Source[] { resolve(url) });
|
||||
}
|
||||
|
||||
public Schema createSchema(final URI uri) {
|
||||
return createSchema(new Source[] { resolveInRepository(uri) });
|
||||
}
|
||||
|
||||
public Schema createSchema(final URL url, final LSResourceResolver resourceResolver) {
|
||||
log.info("Load schema from source {}", url.getPath());
|
||||
return createSchema(new Source[] { resolve(url) }, resourceResolver);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 (this.reportInputSchema == null) {
|
||||
final Source source = resolve(ContentRepository.class.getResource("/xsd/createReportInput.xsd"));
|
||||
this.reportInputSchema = createSchema(new Source[] { source }, new ClassPathResourceResolver("/xsd"));
|
||||
}
|
||||
return this.reportInputSchema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Erzeugt ein Schema auf Basis der übegebenen URIs
|
||||
*
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ package de.kosit.validationtool.impl;
|
|||
import static de.kosit.validationtool.impl.DateFactory.createTimestamp;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
|
@ -42,6 +43,7 @@ import de.kosit.validationtool.impl.tasks.ScenarioSelectionAction;
|
|||
import de.kosit.validationtool.impl.tasks.SchemaValidationAction;
|
||||
import de.kosit.validationtool.impl.tasks.SchematronValidationAction;
|
||||
import de.kosit.validationtool.impl.tasks.ValidateReportInputAction;
|
||||
import de.kosit.validationtool.impl.xml.ProcessorProvider;
|
||||
import de.kosit.validationtool.model.reportInput.CreateReportInput;
|
||||
import de.kosit.validationtool.model.reportInput.EngineType;
|
||||
import de.kosit.validationtool.model.reportInput.XMLSyntaxError;
|
||||
|
|
@ -61,31 +63,36 @@ public class DefaultCheck implements Check {
|
|||
private final ConversionService conversionService;
|
||||
|
||||
@Getter
|
||||
private final Configuration configuration;
|
||||
private final List<Configuration> configuration;
|
||||
|
||||
@Getter
|
||||
private final List<CheckAction> checkSteps;
|
||||
|
||||
@Getter
|
||||
private final Processor processor;
|
||||
|
||||
public DefaultCheck(final Configuration... configuration) {
|
||||
this(ProcessorProvider.getProcessor(), configuration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance for the {@link Configuration}.
|
||||
*
|
||||
* @param configuration the Configuration
|
||||
*/
|
||||
public DefaultCheck(final Configuration configuration) {
|
||||
this.configuration = configuration;
|
||||
final ContentRepository content = configuration.getContentRepository();
|
||||
final Processor processor = content.getProcessor();
|
||||
public DefaultCheck(final Processor processor, final Configuration... configuration) {
|
||||
this.configuration = Arrays.asList(configuration);
|
||||
this.processor = processor;
|
||||
this.conversionService = new ConversionService();
|
||||
|
||||
this.checkSteps = new ArrayList<>();
|
||||
this.checkSteps.add(new DocumentParseAction(processor));
|
||||
this.checkSteps.add(new CreateDocumentIdentificationAction());
|
||||
this.checkSteps.add(new ScenarioSelectionAction(new ScenarioRepository(configuration)));
|
||||
this.checkSteps.add(new SchemaValidationAction(content.getResolvingConfigurationStrategy(), processor));
|
||||
this.checkSteps.add(new SchematronValidationAction(content.getResolver(), this.conversionService));
|
||||
this.checkSteps.add(new ValidateReportInputAction(this.conversionService, content.getReportInputSchema()));
|
||||
this.checkSteps.add(
|
||||
new CreateReportAction(processor, this.conversionService, content.getResolver(), content.getUnparsedTextURIResolver()));
|
||||
this.checkSteps.add(new SchemaValidationAction(processor));
|
||||
this.checkSteps.add(new SchematronValidationAction(this.conversionService));
|
||||
this.checkSteps.add(new ValidateReportInputAction(this.conversionService, SchemaProvider.getReportInputSchema()));
|
||||
this.checkSteps.add(new CreateReportAction(processor, this.conversionService));
|
||||
this.checkSteps.add(new ComputeAcceptanceAction());
|
||||
}
|
||||
|
||||
|
|
@ -125,8 +132,7 @@ public class DefaultCheck implements Check {
|
|||
}
|
||||
|
||||
private Result createResult(final Bag t) {
|
||||
final DefaultResult result = new DefaultResult(t.getReport(), t.getAcceptStatus(),
|
||||
new HtmlExtractor(this.configuration.getContentRepository().getProcessor()));
|
||||
final DefaultResult result = new DefaultResult(t.getReport(), t.getAcceptStatus(), new HtmlExtractor(this.processor));
|
||||
result.setWellformed(t.getParserResult().isValid());
|
||||
result.setReportInput(t.getReportInput());
|
||||
if (t.getSchemaValidationResult() != null) {
|
||||
|
|
|
|||
|
|
@ -50,4 +50,20 @@ public class Printer {
|
|||
public static void writeErr(final String message, final Object... params) {
|
||||
System.err.println(new MessageFormat(message, Locale.ENGLISH).format(params));
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes to standard error channel and prints a stacktrace.
|
||||
*
|
||||
* @param ex the exception
|
||||
* @param message the message with placeholders
|
||||
* @param params the params
|
||||
*/
|
||||
@SuppressWarnings("squid:S1148")
|
||||
public static void writeErr(final Exception ex, final String message, final Object... params) {
|
||||
writeErr(message, params);
|
||||
if (ex != null) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import java.util.Collections;
|
|||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.xml.transform.URIResolver;
|
||||
import javax.xml.validation.Schema;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
|
|
@ -27,9 +28,11 @@ import lombok.Getter;
|
|||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
import de.kosit.validationtool.api.ResolvingConfigurationStrategy;
|
||||
import de.kosit.validationtool.model.scenarios.ResourceType;
|
||||
import de.kosit.validationtool.model.scenarios.ScenarioType;
|
||||
|
||||
import net.sf.saxon.lib.UnparsedTextURIResolver;
|
||||
import net.sf.saxon.s9api.XPathExecutable;
|
||||
import net.sf.saxon.s9api.XPathSelector;
|
||||
import net.sf.saxon.s9api.XsltExecutable;
|
||||
|
|
@ -65,6 +68,12 @@ public class Scenario {
|
|||
|
||||
private XPathExecutable acceptExecutable;
|
||||
|
||||
private ResolvingConfigurationStrategy factory;
|
||||
|
||||
private URIResolver uriResolver;
|
||||
|
||||
private UnparsedTextURIResolver unparsedTextURIResolver;
|
||||
|
||||
@Setter
|
||||
private List<Transformation> schematronValidations;
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package de.kosit.validationtool.impl;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
|
@ -38,20 +39,30 @@ import net.sf.saxon.s9api.XdmNode;
|
|||
|
||||
public class ScenarioRepository {
|
||||
|
||||
private final Configuration configuration;
|
||||
public static final String DEFAULT = "default";
|
||||
|
||||
public ScenarioRepository(final Configuration configuration) {
|
||||
this.configuration = configuration;
|
||||
log.info("Loaded scenarios for {} by {} from {}. The following scenarios are available:\n\n{}", configuration.getName(),
|
||||
configuration.getAuthor(), configuration.getDate(), summarizeScenarios());
|
||||
public static final String DEFAULT_ID = DEFAULT + "_1";
|
||||
|
||||
private final List<Configuration> configuration;
|
||||
|
||||
public ScenarioRepository(final Configuration... configuration) {
|
||||
if (configuration.length == 0) {
|
||||
throw new IllegalArgumentException("Must provide at least one configuration");
|
||||
}
|
||||
this.configuration = Arrays.asList(configuration);
|
||||
this.configuration.forEach(v -> log.info("Loaded scenarios for {} by {} from {}.", v.getName(), v.getAuthor(), v.getDate()));
|
||||
log.info("The following scenarios are available:\n{}", summarizeScenarios());
|
||||
}
|
||||
|
||||
public Scenario getFallbackScenario() {
|
||||
return this.configuration.getFallbackScenario();
|
||||
if (this.configuration.size() > 1) {
|
||||
log.warn("Multiple configurations found. Using fallback scenario from first configuration");
|
||||
}
|
||||
return this.configuration.get(0).getFallbackScenario();
|
||||
}
|
||||
|
||||
public List<Scenario> getScenarios() {
|
||||
return this.configuration.getScenarios();
|
||||
return this.configuration.stream().flatMap(c -> c.getScenarios().stream()).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private String summarizeScenarios() {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* Copyright 2017-2020 Koordinierungsstelle für IT-Standards (KoSIT)
|
||||
*
|
||||
* Licensed 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.URISyntaxException;
|
||||
import java.net.URL;
|
||||
|
||||
import javax.xml.transform.Source;
|
||||
import javax.xml.transform.stream.StreamSource;
|
||||
import javax.xml.validation.Schema;
|
||||
import javax.xml.validation.SchemaFactory;
|
||||
|
||||
import org.w3c.dom.ls.LSResourceResolver;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import de.kosit.validationtool.impl.xml.ClassPathResourceResolver;
|
||||
|
||||
/**
|
||||
* @author Andreas Penski
|
||||
*/
|
||||
public class SchemaProvider {
|
||||
|
||||
private static Schema reportInputSchema;
|
||||
|
||||
/**
|
||||
* Liefert das definierte Schema für die Validierung des [@link CreateReportInput}
|
||||
*
|
||||
* @return ReportInput-Schema
|
||||
*/
|
||||
public static Schema getReportInputSchema() {
|
||||
if (reportInputSchema == null) {
|
||||
final SchemaFactory sf = ResolvingMode.STRICT_RELATIVE.getStrategy().createSchemaFactory();
|
||||
final Source source = resolve(SchemaProvider.class.getResource("/xsd/createReportInput.xsd"));
|
||||
reportInputSchema = createSchema(sf, new Source[] { source }, new ClassPathResourceResolver("/xsd"));
|
||||
}
|
||||
return reportInputSchema;
|
||||
}
|
||||
|
||||
private static Schema createSchema(final SchemaFactory sf, final Source[] schemaSources, final LSResourceResolver resourceResolver) {
|
||||
try {
|
||||
sf.setResourceResolver(resourceResolver);
|
||||
return sf.newSchema(schemaSources);
|
||||
} catch (final SAXException e) {
|
||||
throw new IllegalArgumentException("Can not load schema from sources " + schemaSources[0].getSystemId(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private static Schema createSchema(final SchemaFactory sf, final Source... schemaSources) {
|
||||
return createSchema(sf, schemaSources, null);
|
||||
}
|
||||
|
||||
@SuppressWarnings("java:S2095") // xml stack requires not closing the resource here
|
||||
private static Source resolve(final URL resource) {
|
||||
try {
|
||||
final String rawPath = resource.toURI().getRawPath();
|
||||
return new StreamSource(resource.openStream(), rawPath);
|
||||
} catch (final IOException | URISyntaxException e) {
|
||||
throw new IllegalStateException("Can not load schema for resource " + resource.getPath(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Liefert das definiert Schema für die Szenario-Konfiguration
|
||||
*
|
||||
* @return Scenario-Schema
|
||||
*/
|
||||
public static Schema getScenarioSchema() {
|
||||
final SchemaFactory sf = ResolvingMode.STRICT_RELATIVE.getStrategy().createSchemaFactory();
|
||||
return createSchema(sf, resolve(SchemaProvider.class.getResource("/xsd/scenarios.xsd")));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -23,7 +23,6 @@ import java.util.stream.Collectors;
|
|||
import javax.xml.bind.JAXBException;
|
||||
import javax.xml.bind.Marshaller;
|
||||
import javax.xml.bind.util.JAXBSource;
|
||||
import javax.xml.transform.URIResolver;
|
||||
|
||||
import org.xml.sax.ContentHandler;
|
||||
import org.xml.sax.DTDHandler;
|
||||
|
|
@ -45,7 +44,6 @@ import de.kosit.validationtool.impl.EngineInformation;
|
|||
import de.kosit.validationtool.impl.Scenario;
|
||||
import de.kosit.validationtool.model.reportInput.XMLSyntaxError;
|
||||
|
||||
import net.sf.saxon.lib.UnparsedTextURIResolver;
|
||||
import net.sf.saxon.s9api.BuildingContentHandler;
|
||||
import net.sf.saxon.s9api.DocumentBuilder;
|
||||
import net.sf.saxon.s9api.Processor;
|
||||
|
|
@ -172,10 +170,6 @@ public class CreateReportAction implements CheckAction {
|
|||
|
||||
private final ConversionService conversionService;
|
||||
|
||||
private final URIResolver resolver;
|
||||
|
||||
private final UnparsedTextURIResolver unparsedTextURIResolver;
|
||||
|
||||
private static XsltExecutable loadFromScenario(final Scenario object) {
|
||||
return object.getReportTransformation().getExecutable();
|
||||
}
|
||||
|
|
@ -198,9 +192,11 @@ public class CreateReportAction implements CheckAction {
|
|||
transformer.setInitialContextNode(root);
|
||||
final CollectingErrorEventHandler e = new CollectingErrorEventHandler();
|
||||
transformer.setMessageListener(e);
|
||||
transformer.setURIResolver(this.resolver);
|
||||
if (this.unparsedTextURIResolver != null) {
|
||||
transformer.getUnderlyingController().setUnparsedTextURIResolver(this.unparsedTextURIResolver);
|
||||
final Scenario scenario = results.getScenarioSelectionResult().getObject();
|
||||
transformer.setURIResolver(scenario.getUriResolver());
|
||||
|
||||
if (scenario.getUnparsedTextURIResolver() != null) {
|
||||
transformer.getUnderlyingController().setUnparsedTextURIResolver(scenario.getUnparsedTextURIResolver());
|
||||
}
|
||||
if (parsedDocument != null) {
|
||||
transformer.setParameter(new QName("input-document"), parsedDocument);
|
||||
|
|
|
|||
|
|
@ -38,7 +38,6 @@ import lombok.Setter;
|
|||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import de.kosit.validationtool.api.Input;
|
||||
import de.kosit.validationtool.api.ResolvingConfigurationStrategy;
|
||||
import de.kosit.validationtool.impl.CollectingErrorEventHandler;
|
||||
import de.kosit.validationtool.impl.Scenario;
|
||||
import de.kosit.validationtool.impl.input.AbstractInput;
|
||||
|
|
@ -134,8 +133,6 @@ public class SchemaValidationAction implements CheckAction {
|
|||
|
||||
private static final String LIMIT_PARAMETER = "schema.validation.inmem.limit";
|
||||
|
||||
private final ResolvingConfigurationStrategy factory;
|
||||
|
||||
private final Processor processor;
|
||||
|
||||
@Setter(AccessLevel.PACKAGE)
|
||||
|
|
@ -147,7 +144,7 @@ public class SchemaValidationAction implements CheckAction {
|
|||
final CollectingErrorEventHandler errorHandler = new CollectingErrorEventHandler();
|
||||
try ( final SourceProvider validateInput = resolveSource(results) ) {
|
||||
|
||||
final Validator validator = this.factory.createValidator(scenario.getSchema());
|
||||
final Validator validator = scenario.getFactory().createValidator(scenario.getSchema());
|
||||
validator.setErrorHandler(errorHandler);
|
||||
validator.validate(validateInput.getSource());
|
||||
return new Result<>(!errorHandler.hasErrors(), errorHandler.getErrors());
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ package de.kosit.validationtool.impl.tasks;
|
|||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.xml.transform.URIResolver;
|
||||
import javax.xml.transform.dom.DOMSource;
|
||||
|
||||
import org.oclc.purl.dsdl.svrl.SchematronOutput;
|
||||
|
|
@ -30,6 +29,7 @@ import lombok.extern.slf4j.Slf4j;
|
|||
import de.kosit.validationtool.impl.CollectingErrorEventHandler;
|
||||
import de.kosit.validationtool.impl.ConversionService;
|
||||
import de.kosit.validationtool.impl.Scenario;
|
||||
import de.kosit.validationtool.impl.Scenario.Transformation;
|
||||
import de.kosit.validationtool.model.reportInput.CreateReportInput;
|
||||
import de.kosit.validationtool.model.reportInput.ValidationResultsSchematron;
|
||||
import de.kosit.validationtool.model.reportInput.ValidationResultsSchematron.Results;
|
||||
|
|
@ -49,21 +49,20 @@ import net.sf.saxon.s9api.XsltTransformer;
|
|||
@Slf4j
|
||||
public class SchematronValidationAction implements CheckAction {
|
||||
|
||||
private final URIResolver resolver;
|
||||
|
||||
private final ConversionService conversionService;
|
||||
|
||||
private List<ValidationResultsSchematron> validate(final Bag results, final XdmNode document, final Scenario scenario) {
|
||||
return scenario.getSchematronValidations().stream().map(v -> validate(results, document, v)).collect(Collectors.toList());
|
||||
return scenario.getSchematronValidations().stream().map(v -> validate(scenario, results, document, v)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private ValidationResultsSchematron validate(final Bag results, final XdmNode document, final Scenario.Transformation validation) {
|
||||
private ValidationResultsSchematron validate(final Scenario scenario, final Bag results, final XdmNode document,
|
||||
final Transformation validation) {
|
||||
final ValidationResultsSchematron s = new ValidationResultsSchematron();
|
||||
s.setResource(validation.getResourceType());
|
||||
try {
|
||||
final XsltTransformer transformer = validation.getExecutable().load();
|
||||
// resolving nur relative zum Repository
|
||||
transformer.setURIResolver(this.resolver);
|
||||
transformer.setURIResolver(scenario.getUriResolver());
|
||||
final CollectingErrorEventHandler e = new CollectingErrorEventHandler();
|
||||
transformer.setMessageListener(e);
|
||||
|
||||
|
|
|
|||
|
|
@ -28,34 +28,14 @@ import lombok.extern.slf4j.Slf4j;
|
|||
|
||||
import de.kosit.validationtool.api.ResolvingConfigurationStrategy;
|
||||
|
||||
import net.sf.saxon.s9api.Processor;
|
||||
|
||||
/**
|
||||
* @author Andreas Penski
|
||||
*/
|
||||
@Slf4j
|
||||
public abstract class BaseResolvingStrategy implements ResolvingConfigurationStrategy {
|
||||
|
||||
protected static final String DISSALLOW_DOCTYPE_DECL_FEATURE = "http://apache.org/xml/features/disallow-doctype-decl";
|
||||
|
||||
protected static final String LOAD_EXTERNAL_DTD_FEATURE = "http://apache.org/xml/features/nonvalidating/load-external-dtd";
|
||||
|
||||
protected static final String FEATURE_SECURE_PROCESSING = "http://javax.xml.XMLConstants/feature/secure-processing";
|
||||
|
||||
private static final String ORACLE_XERCES_CLASS = "com.sun.org.apache.xerces.internal.impl.Constants";
|
||||
|
||||
private Processor processor;
|
||||
|
||||
@Override
|
||||
public Processor getProcessor() {
|
||||
if (this.processor == null) {
|
||||
this.processor = createProcessor();
|
||||
}
|
||||
return this.processor;
|
||||
}
|
||||
|
||||
protected abstract Processor createProcessor();
|
||||
|
||||
public static void forceOpenJdkXmlImplementation() {
|
||||
if (!isOpenJdkXmlImplementationAvailable()) {
|
||||
throw new IllegalStateException("No OpenJDK version of XERCES found");
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package de.kosit.validationtool.impl;
|
||||
package de.kosit.validationtool.impl.xml;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
|
@ -31,15 +31,13 @@ import lombok.RequiredArgsConstructor;
|
|||
import lombok.Setter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import de.kosit.validationtool.impl.xml.RelativeUriResolver;
|
||||
|
||||
/**
|
||||
* {@link LSResourceResolver} der objekte relativ zu einem Basis-Pfad aus dem Classpath der Anwendung laden kann.
|
||||
*
|
||||
* @author Andreas Penski
|
||||
*/
|
||||
@Slf4j
|
||||
class ClassPathResourceResolver implements LSResourceResolver {
|
||||
public class ClassPathResourceResolver implements LSResourceResolver {
|
||||
|
||||
/**
|
||||
* Simple {@link LSInput}-Implementierung, die einen Stream liefern kann
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* Copyright 2017-2020 Koordinierungsstelle für IT-Standards (KoSIT)
|
||||
*
|
||||
* Licensed 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.xml;
|
||||
|
||||
import java.io.Reader;
|
||||
import java.net.URI;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import javax.xml.XMLConstants;
|
||||
import javax.xml.transform.Result;
|
||||
import javax.xml.transform.TransformerException;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
import net.sf.saxon.Configuration;
|
||||
import net.sf.saxon.expr.XPathContext;
|
||||
import net.sf.saxon.lib.CollectionFinder;
|
||||
import net.sf.saxon.lib.Feature;
|
||||
import net.sf.saxon.lib.FeatureKeys;
|
||||
import net.sf.saxon.lib.OutputURIResolver;
|
||||
import net.sf.saxon.lib.ResourceCollection;
|
||||
import net.sf.saxon.lib.UnparsedTextURIResolver;
|
||||
import net.sf.saxon.s9api.Processor;
|
||||
import net.sf.saxon.trans.XPathException;
|
||||
|
||||
/**
|
||||
* @author Andreas Penski
|
||||
*/
|
||||
public class ProcessorProvider {
|
||||
|
||||
private static class SecureUriResolver implements CollectionFinder, OutputURIResolver, UnparsedTextURIResolver {
|
||||
|
||||
public static final String MESSAGE = "Configuration error. Resolving ist not allowed";
|
||||
|
||||
@Override
|
||||
public OutputURIResolver newInstance() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result resolve(final String href, final String base) throws TransformerException {
|
||||
throw new IllegalStateException(MESSAGE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close(final Result result) throws TransformerException {
|
||||
throw new IllegalStateException(MESSAGE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Reader resolve(final URI absoluteURI, final String encoding, final Configuration config) throws XPathException {
|
||||
throw new IllegalStateException(MESSAGE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceCollection findCollection(final XPathContext context, final String collectionURI) throws XPathException {
|
||||
throw new IllegalStateException(MESSAGE);
|
||||
}
|
||||
}
|
||||
|
||||
protected static final String DISSALLOW_DOCTYPE_DECL_FEATURE = "http://apache.org/xml/features/disallow-doctype-decl";
|
||||
|
||||
protected static final String LOAD_EXTERNAL_DTD_FEATURE = "http://apache.org/xml/features/nonvalidating/load-external-dtd";
|
||||
|
||||
protected static final String FEATURE_SECURE_PROCESSING = "http://javax.xml.XMLConstants/feature/secure-processing";
|
||||
|
||||
private static Processor processor;
|
||||
|
||||
@SneakyThrows
|
||||
private static String encode(final String input) {
|
||||
return URLEncoder.encode(input, StandardCharsets.UTF_8.name());
|
||||
}
|
||||
|
||||
public static Processor getProcessor() {
|
||||
if (processor == null) {
|
||||
processor = createProcessor();
|
||||
}
|
||||
return processor;
|
||||
}
|
||||
|
||||
private static Processor createProcessor() {
|
||||
final Processor processor = new Processor(false);
|
||||
// verhindere global im Prinzip alle resolving strategien
|
||||
final SecureUriResolver resolver = new SecureUriResolver();
|
||||
processor.getUnderlyingConfiguration().setCollectionFinder(resolver);
|
||||
processor.getUnderlyingConfiguration().setOutputURIResolver(resolver);// NOSONAR
|
||||
processor.getUnderlyingConfiguration().setUnparsedTextURIResolver(resolver);
|
||||
|
||||
// grundsätzlich Feature-konfiguration:
|
||||
processor.setConfigurationProperty(Feature.DTD_VALIDATION, false);
|
||||
processor.setConfigurationProperty(Feature.ENTITY_RESOLVER_CLASS, "");
|
||||
processor.setConfigurationProperty(Feature.XINCLUDE, false);
|
||||
processor.setConfigurationProperty(Feature.ALLOW_EXTERNAL_FUNCTIONS, false);
|
||||
|
||||
// Konfiguration des zu verwendenden Parsers, wenn Saxon selbst einen erzeugen muss, bspw. beim XSL parsen
|
||||
processor.setConfigurationProperty(FeatureKeys.XML_PARSER_FEATURE + encode(FEATURE_SECURE_PROCESSING), true); // NOSONAR
|
||||
processor.setConfigurationProperty(FeatureKeys.XML_PARSER_FEATURE + encode(DISSALLOW_DOCTYPE_DECL_FEATURE), true);// NOSONAR
|
||||
processor.setConfigurationProperty(FeatureKeys.XML_PARSER_FEATURE + encode(LOAD_EXTERNAL_DTD_FEATURE), false);// NOSONAR
|
||||
processor.setConfigurationProperty(FeatureKeys.XML_PARSER_FEATURE + encode(XMLConstants.ACCESS_EXTERNAL_DTD), false);// NOSONAR
|
||||
return processor;
|
||||
}
|
||||
}
|
||||
|
|
@ -16,32 +16,17 @@
|
|||
|
||||
package de.kosit.validationtool.impl.xml;
|
||||
|
||||
import java.io.Reader;
|
||||
import java.net.URI;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import javax.xml.XMLConstants;
|
||||
import javax.xml.transform.Result;
|
||||
import javax.xml.transform.TransformerException;
|
||||
import javax.xml.transform.URIResolver;
|
||||
import javax.xml.validation.Schema;
|
||||
import javax.xml.validation.SchemaFactory;
|
||||
import javax.xml.validation.Validator;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
import net.sf.saxon.Configuration;
|
||||
import net.sf.saxon.expr.XPathContext;
|
||||
import net.sf.saxon.lib.CollectionFinder;
|
||||
import net.sf.saxon.lib.Feature;
|
||||
import net.sf.saxon.lib.FeatureKeys;
|
||||
import net.sf.saxon.lib.OutputURIResolver;
|
||||
import net.sf.saxon.lib.ResourceCollection;
|
||||
import net.sf.saxon.lib.UnparsedTextURIResolver;
|
||||
import net.sf.saxon.s9api.Processor;
|
||||
import net.sf.saxon.trans.XPathException;
|
||||
|
||||
/**
|
||||
* @author Andreas Penski
|
||||
|
|
@ -49,78 +34,16 @@ import net.sf.saxon.trans.XPathException;
|
|||
@RequiredArgsConstructor
|
||||
public class StrictRelativeResolvingStrategy extends BaseResolvingStrategy {
|
||||
|
||||
private static class SecureUriResolver implements CollectionFinder, OutputURIResolver, UnparsedTextURIResolver {
|
||||
|
||||
public static final String MESSAGE = "Configuration error. Resolving ist not allowed";
|
||||
|
||||
@Override
|
||||
public OutputURIResolver newInstance() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result resolve(final String href, final String base) throws TransformerException {
|
||||
throw new IllegalStateException(MESSAGE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close(final Result result) throws TransformerException {
|
||||
throw new IllegalStateException(MESSAGE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Reader resolve(final URI absoluteURI, final String encoding, final Configuration config) throws XPathException {
|
||||
throw new IllegalStateException(MESSAGE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceCollection findCollection(final XPathContext context, final String collectionURI) throws XPathException {
|
||||
throw new IllegalStateException(MESSAGE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* e.g. don't allow any scheme
|
||||
*/
|
||||
private static final String EMPTY_SCHEME = "";
|
||||
|
||||
@Override
|
||||
public SchemaFactory createSchemaFactory() {
|
||||
forceOpenJdkXmlImplementation();
|
||||
@SuppressWarnings("java:S2755") //
|
||||
final SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
|
||||
disableExternalEntities(sf);
|
||||
allowExternalSchema(sf, "file");
|
||||
return sf;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Processor createProcessor() {
|
||||
final Processor processor = new Processor(false);
|
||||
// verhindere global im Prinzip alle resolving strategien
|
||||
final SecureUriResolver resolver = new SecureUriResolver();
|
||||
processor.getUnderlyingConfiguration().setCollectionFinder(resolver);
|
||||
processor.getUnderlyingConfiguration().setOutputURIResolver(resolver);// NOSONAR
|
||||
processor.getUnderlyingConfiguration().setUnparsedTextURIResolver(resolver);
|
||||
|
||||
// grundsätzlich Feature-konfiguration:
|
||||
processor.setConfigurationProperty(Feature.DTD_VALIDATION, false);
|
||||
processor.setConfigurationProperty(Feature.ENTITY_RESOLVER_CLASS, "");
|
||||
processor.setConfigurationProperty(Feature.XINCLUDE, false);
|
||||
processor.setConfigurationProperty(Feature.ALLOW_EXTERNAL_FUNCTIONS, false);
|
||||
|
||||
// Konfiguration des zu verwendenden Parsers, wenn Saxon selbst einen erzeugen muss, bspw. beim XSL parsen
|
||||
processor.setConfigurationProperty(FeatureKeys.XML_PARSER_FEATURE + encode(FEATURE_SECURE_PROCESSING), true); // NOSONAR
|
||||
processor.setConfigurationProperty(FeatureKeys.XML_PARSER_FEATURE + encode(DISSALLOW_DOCTYPE_DECL_FEATURE), true);// NOSONAR
|
||||
processor.setConfigurationProperty(FeatureKeys.XML_PARSER_FEATURE + encode(LOAD_EXTERNAL_DTD_FEATURE), false);// NOSONAR
|
||||
processor.setConfigurationProperty(FeatureKeys.XML_PARSER_FEATURE + encode(XMLConstants.ACCESS_EXTERNAL_DTD), false);// NOSONAR
|
||||
return processor;
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private static String encode(final String input) {
|
||||
return URLEncoder.encode(input, StandardCharsets.UTF_8.name());
|
||||
}
|
||||
|
||||
@Override
|
||||
public URIResolver createResolver(final URI repositoryURI) {
|
||||
return new RelativeUriResolver(repositoryURI);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue