mirror of
https://github.com/itplr-kosit/validator.git
synced 2026-05-25 16:55:39 +00:00
(enhance) introduce resolving strategy (configurable xml security); introduce API configuration
This commit is contained in:
parent
7a86f049ac
commit
35c0797898
67 changed files with 2441 additions and 845 deletions
|
|
@ -1,92 +0,0 @@
|
|||
package de.kosit.validationtool.config;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import de.kosit.validationtool.api.Configuration;
|
||||
import de.kosit.validationtool.impl.ObjectFactory;
|
||||
import de.kosit.validationtool.impl.Scenario;
|
||||
|
||||
import net.sf.saxon.s9api.Processor;
|
||||
|
||||
/**
|
||||
* Base configuration class.
|
||||
*
|
||||
* @author Andreas Penski
|
||||
*/
|
||||
@Slf4j
|
||||
public abstract class BaseConfiguration implements Configuration {
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
@Setter
|
||||
protected static class RuntimeArtefacts {
|
||||
|
||||
private final List<Scenario> scenarios;
|
||||
|
||||
private final Scenario fallbackScenario;
|
||||
|
||||
private String name;
|
||||
|
||||
private String author;
|
||||
|
||||
private String date;
|
||||
}
|
||||
|
||||
private RuntimeArtefacts artefacts;
|
||||
|
||||
protected abstract RuntimeArtefacts buildArtefacts();
|
||||
|
||||
@Override
|
||||
public void build() {
|
||||
if (this.artefacts != null) {
|
||||
log.warn("Configuration already complete. Will drop previous artefacts and build again");
|
||||
}
|
||||
this.artefacts = buildArtefacts();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Scenario> getScenarios() {
|
||||
assertBuild();
|
||||
return this.artefacts.getScenarios();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Scenario getFallbackScenario() {
|
||||
assertBuild();
|
||||
return this.artefacts.getFallbackScenario();
|
||||
}
|
||||
|
||||
private void assertBuild() {
|
||||
if (this.artefacts == null) {
|
||||
throw new IllegalStateException("Configuration");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Processor getProcessor() {
|
||||
return ObjectFactory.createProcessor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAuthor() {
|
||||
assertBuild();
|
||||
return this.artefacts.getAuthor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
assertBuild();
|
||||
return this.artefacts.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDate() {
|
||||
assertBuild();
|
||||
return this.artefacts.getDate();
|
||||
}
|
||||
}
|
||||
12
src/main/java/de/kosit/validationtool/config/Builder.java
Normal file
12
src/main/java/de/kosit/validationtool/config/Builder.java
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
package de.kosit.validationtool.config;
|
||||
|
||||
import de.kosit.validationtool.impl.ContentRepository;
|
||||
import de.kosit.validationtool.impl.model.Result;
|
||||
|
||||
/**
|
||||
* @author Andreas Penski
|
||||
*/
|
||||
public interface Builder<T> {
|
||||
|
||||
Result<T, String> build(ContentRepository repository);
|
||||
}
|
||||
|
|
@ -1,10 +1,245 @@
|
|||
package de.kosit.validationtool.config;
|
||||
|
||||
import java.net.URI;
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.xml.validation.Schema;
|
||||
|
||||
import org.apache.commons.lang3.NotImplementedException;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import de.kosit.validationtool.api.Configuration;
|
||||
import de.kosit.validationtool.api.ResolvingConfigurationStrategy;
|
||||
import de.kosit.validationtool.impl.ContentRepository;
|
||||
import de.kosit.validationtool.impl.ResolvingMode;
|
||||
import de.kosit.validationtool.impl.Scenario;
|
||||
import de.kosit.validationtool.impl.model.Result;
|
||||
|
||||
import net.sf.saxon.s9api.Processor;
|
||||
|
||||
/**
|
||||
* Implements a builder style creation of a {@link Configuration}.
|
||||
*
|
||||
* @author Andreas Penski
|
||||
*/
|
||||
@Slf4j
|
||||
public class ConfigurationBuilder {
|
||||
|
||||
private ScenarioBuilder scenarioBuilder;
|
||||
private final List<ScenarioBuilder> scenarios = new ArrayList<>();
|
||||
|
||||
private FallbackBuilder fallbackBuilder;
|
||||
|
||||
private ResolvingConfigurationStrategy resolvingConfigurationStrategy;
|
||||
|
||||
private ResolvingMode resolvingMode = ResolvingMode.STRICT_RELATIVE;
|
||||
|
||||
private Processor processor;
|
||||
|
||||
private String author = "API";
|
||||
|
||||
private String date = LocalDate.now().toString();
|
||||
|
||||
private String name = "Custom";
|
||||
|
||||
private final Map<String, Object> parameters = new HashMap<>();
|
||||
|
||||
private URI repository;
|
||||
|
||||
public ConfigurationBuilder author(final String authorName) {
|
||||
this.author = authorName;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ConfigurationBuilder date(final LocalDate localDate) {
|
||||
this.date = localDate.toString();
|
||||
return this;
|
||||
}
|
||||
|
||||
public ConfigurationBuilder name(final String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ConfigurationBuilder date(final Date date) {
|
||||
return date(LocalDate.ofEpochDay(date.getTime()));
|
||||
}
|
||||
|
||||
public ConfigurationBuilder with(final ScenarioBuilder scenarioBuilder) {
|
||||
this.scenarios.add(scenarioBuilder);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ConfigurationBuilder with(final FallbackBuilder builder) {
|
||||
if (this.fallbackBuilder != null) {
|
||||
log.warn("Overriding previously created fallback scenario");
|
||||
}
|
||||
this.fallbackBuilder = builder;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a fallback scenario configuration.
|
||||
*
|
||||
* @return the builder
|
||||
*/
|
||||
public static FallbackBuilder fallback() {
|
||||
return new FallbackBuilder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the default fallback configuration if new scenario match. Note: this is public for explicit usage. If no
|
||||
* fallback is configured, this is the still default fallback.
|
||||
*
|
||||
* @return a fallback configuration
|
||||
*/
|
||||
public static FallbackBuilder defaultFallback() {
|
||||
throw new NotImplementedException("Not yet defined");
|
||||
}
|
||||
|
||||
public static SchematronBuilder schematron(final String name) {
|
||||
return new SchematronBuilder().name(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new schema validation configuration.
|
||||
*
|
||||
* @return a configuration builder for schema
|
||||
*/
|
||||
public static SchemaBuilder schema() {
|
||||
return new SchemaBuilder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new schema validation configuration.
|
||||
*
|
||||
* @param name the name of the schema
|
||||
* @param schema the actual precompiled schema to use
|
||||
* @return a configuration builder for schema
|
||||
*/
|
||||
public static SchemaBuilder schema(final String name, final Schema schema) {
|
||||
return new SchemaBuilder().name(name).schema(schema);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new schema validation configuration.
|
||||
*
|
||||
* @param name the name of the schema
|
||||
* @return a configuration builder for schema
|
||||
*/
|
||||
public static SchemaBuilder schema(final String name) {
|
||||
return new SchemaBuilder().name(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new schema validation configuration.
|
||||
*
|
||||
* @param uri the uri location of the schema
|
||||
* @return a configuration builder for schema
|
||||
*/
|
||||
public static SchemaBuilder schema(final URI uri) {
|
||||
return new SchemaBuilder().schemaLocation(uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new named scenario configuration.
|
||||
*
|
||||
* @param name the name of the scenario
|
||||
* @return the scenario configuration builder
|
||||
*/
|
||||
public static ScenarioBuilder scenario(final String name) {
|
||||
return new ScenarioBuilder(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create named report configuration.
|
||||
*
|
||||
* @param name the name of the report
|
||||
* @return the report configuration builder
|
||||
*/
|
||||
public static ReportBuilder report(final String name) {
|
||||
return new ReportBuilder().name(name);
|
||||
}
|
||||
|
||||
public Configuration build() {
|
||||
final ResolvingConfigurationStrategy resolving = getResolvingConfigurationStrategy();
|
||||
if (this.processor == null) {
|
||||
this.processor = resolving.createProcessor();
|
||||
}
|
||||
final ContentRepository contentRepository = new ContentRepository(this.processor, this.repository,
|
||||
resolving.createResolver(this.repository));
|
||||
contentRepository.setSchemaFactory(resolving.createSchemaFactory());
|
||||
contentRepository.setResolvingConfigurationStrategy(resolving);
|
||||
|
||||
final List<Scenario> list = initializeScenarios(contentRepository);
|
||||
final Scenario fallbackScenario = initializeFallback(contentRepository);
|
||||
final DefaultConfiguration configuration = new DefaultConfiguration(list, fallbackScenario);
|
||||
configuration.setAdditionalParameters(this.parameters);
|
||||
configuration.setAuthor(this.author);
|
||||
configuration.setDate(this.date);
|
||||
configuration.setName(this.name);
|
||||
configuration.setContentRepository(contentRepository);
|
||||
return (configuration);
|
||||
}
|
||||
|
||||
private Scenario initializeFallback(final ContentRepository contentRepository) {
|
||||
if (this.fallbackBuilder == null) {
|
||||
throw new IllegalStateException("No fallback configuration specified");
|
||||
}
|
||||
final Result<Scenario, String> result = this.fallbackBuilder.build(contentRepository);
|
||||
if (result.isInvalid()) {
|
||||
throw new IllegalStateException("Invalid fallback configuration: " + String.join(",", result.getErrors()));
|
||||
}
|
||||
return result.getObject();
|
||||
}
|
||||
|
||||
private List<Scenario> initializeScenarios(final ContentRepository contentRepository) {
|
||||
if (this.scenarios.size() == 0) {
|
||||
throw new IllegalStateException("No scenario specified");
|
||||
}
|
||||
return this.scenarios.stream().map(s -> {
|
||||
final Result<Scenario, String> result = s.build(contentRepository);
|
||||
if (result.isInvalid()) {
|
||||
final String msg = String.join(",", result.getErrors());
|
||||
throw new IllegalStateException(String.format("Invalid configuration for scenario %s found: %s", s.getName(), msg));
|
||||
}
|
||||
return result.getObject();
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private ResolvingConfigurationStrategy getResolvingConfigurationStrategy() {
|
||||
if (this.resolvingConfigurationStrategy != null) {
|
||||
log.info("Custom resolving strategy supplied. Please take care of xml security!");
|
||||
return this.resolvingConfigurationStrategy;
|
||||
}
|
||||
log.info("Using resolving strategy {}", this.resolvingMode);
|
||||
return this.resolvingMode.getStrategy();
|
||||
}
|
||||
|
||||
public ConfigurationBuilder resolvingMode(final ResolvingMode mode) {
|
||||
this.resolvingMode = mode;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a specific strategy to use for resolving artefacts for scenarios.
|
||||
*
|
||||
* @param strategy the strategy
|
||||
* @return this
|
||||
*/
|
||||
public ConfigurationBuilder resolvingStrategy(final ResolvingConfigurationStrategy strategy) {
|
||||
this.resolvingConfigurationStrategy = strategy;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ConfigurationBuilder useRepository(final URI repository) {
|
||||
this.repository = repository;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,28 +4,36 @@ import static org.apache.commons.lang3.StringUtils.startsWith;
|
|||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.xml.validation.Schema;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import de.kosit.validationtool.api.Check;
|
||||
import de.kosit.validationtool.api.Configuration;
|
||||
import de.kosit.validationtool.api.InputFactory;
|
||||
import de.kosit.validationtool.api.ResolvingConfigurationStrategy;
|
||||
import de.kosit.validationtool.impl.CollectingErrorEventHandler;
|
||||
import de.kosit.validationtool.impl.ContentRepository;
|
||||
import de.kosit.validationtool.impl.ConversionService;
|
||||
import de.kosit.validationtool.impl.RelativeUriResolver;
|
||||
import de.kosit.validationtool.impl.ResolvingMode;
|
||||
import de.kosit.validationtool.impl.Scenario;
|
||||
import de.kosit.validationtool.impl.model.Result;
|
||||
import de.kosit.validationtool.impl.tasks.DocumentParseAction;
|
||||
import de.kosit.validationtool.impl.xml.RelativeUriResolver;
|
||||
import de.kosit.validationtool.model.reportInput.XMLSyntaxError;
|
||||
import de.kosit.validationtool.model.scenarios.CreateReportType;
|
||||
import de.kosit.validationtool.model.scenarios.ResourceType;
|
||||
import de.kosit.validationtool.model.scenarios.ScenarioType;
|
||||
import de.kosit.validationtool.model.scenarios.Scenarios;
|
||||
|
||||
import net.sf.saxon.s9api.Processor;
|
||||
import net.sf.saxon.s9api.QName;
|
||||
import net.sf.saxon.s9api.XdmNode;
|
||||
import net.sf.saxon.s9api.XdmNodeKind;
|
||||
|
|
@ -36,9 +44,9 @@ import net.sf.saxon.s9api.XdmNodeKind;
|
|||
*
|
||||
* @author Andreas Penski
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class LoadConfiguration extends BaseConfiguration {
|
||||
public class ConfigurationLoader {
|
||||
|
||||
private static final String SUPPORTED_MAJOR_VERSION = "1";
|
||||
|
||||
|
|
@ -55,6 +63,12 @@ public class LoadConfiguration extends BaseConfiguration {
|
|||
*/
|
||||
private final URI scenarioRepository;
|
||||
|
||||
protected ResolvingMode resolvingMode = ResolvingMode.STRICT_RELATIVE;
|
||||
|
||||
protected ResolvingConfigurationStrategy resolvingConfigurationStrategy;
|
||||
|
||||
protected final Map<String, Object> parameters = new HashMap<>();
|
||||
|
||||
URI getScenarioRepository() {
|
||||
if (this.scenarioRepository == null) {
|
||||
log.info("Creating default scenario repository (alongside scenario definition)");
|
||||
|
|
@ -63,9 +77,10 @@ public class LoadConfiguration extends BaseConfiguration {
|
|||
return this.scenarioRepository;
|
||||
}
|
||||
|
||||
private static void checkVersion(final URI scenarioDefinition) {
|
||||
private static void checkVersion(final URI scenarioDefinition, final Processor processor) {
|
||||
try {
|
||||
final Result<XdmNode, XMLSyntaxError> result = DocumentParseAction.parseDocument(InputFactory.read(scenarioDefinition.toURL()));
|
||||
final Result<XdmNode, XMLSyntaxError> result = new DocumentParseAction(processor)
|
||||
.parseDocument(InputFactory.read(scenarioDefinition.toURL()));
|
||||
if (result.isValid() && !isSupportedDocument(result.getObject())) {
|
||||
throw new IllegalStateException(String.format(
|
||||
"Specified scenario configuration %s is not supported.%nThis version only supports definitions of '%s'",
|
||||
|
|
@ -94,54 +109,53 @@ public class LoadConfiguration extends BaseConfiguration {
|
|||
}
|
||||
|
||||
private static Scenario createFallback(final Scenarios scenarios, final ContentRepository repository) {
|
||||
final ScenarioType t = new ScenarioType();
|
||||
t.setName("Fallback-Scenario");
|
||||
t.setMatch("count(/)<0");
|
||||
final CreateReportType reportType = new CreateReportType();
|
||||
reportType.setResource(scenarios.getNoScenarioReport().getResource());
|
||||
// always reject
|
||||
t.setAcceptMatch("count(/)<0");
|
||||
t.setCreateReport(reportType);
|
||||
final Scenario sceanrio = initialize(t, repository);
|
||||
sceanrio.setFallback(true);
|
||||
return sceanrio;
|
||||
final ResourceType noscenarioResource = scenarios.getNoScenarioReport().getResource();
|
||||
return new FallbackBuilder().source(noscenarioResource.getLocation()).name(noscenarioResource.getName()).build(repository)
|
||||
.getObject();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RuntimeArtefacts buildArtefacts() {
|
||||
final ContentRepository contentRepository = buildContentRepository();
|
||||
final Scenarios def = loadScenarios();
|
||||
public Configuration build() {
|
||||
final ResolvingConfigurationStrategy resolving = getResolvingConfigurationStrategy();
|
||||
final Processor processor = resolving.createProcessor();
|
||||
final ContentRepository contentRepository = new ContentRepository(processor, getScenarioRepository(),
|
||||
resolving.createResolver(this.getScenarioRepository()));
|
||||
contentRepository.setSchemaFactory(resolving.createSchemaFactory());
|
||||
contentRepository.setResolvingConfigurationStrategy(resolving);
|
||||
|
||||
final Scenarios def = loadScenarios(contentRepository.getScenarioSchema(), processor);
|
||||
final List<Scenario> scenarios = initializeScenarios(def, contentRepository);
|
||||
final Scenario fallbackScenario = createFallback(def, contentRepository);
|
||||
final RuntimeArtefacts runtimeArtefacts = new RuntimeArtefacts(scenarios, fallbackScenario);
|
||||
runtimeArtefacts.setAuthor(def.getAuthor());
|
||||
runtimeArtefacts.setDate(def.getDate().toString());
|
||||
runtimeArtefacts.setName(def.getName());
|
||||
return runtimeArtefacts;
|
||||
final DefaultConfiguration configuration = new DefaultConfiguration(scenarios, fallbackScenario);
|
||||
configuration.setAdditionalParameters(this.parameters);
|
||||
configuration.setAuthor(def.getAuthor());
|
||||
configuration.setDate(def.getDate().toString());
|
||||
configuration.setName(def.getName());
|
||||
configuration.setContentRepository(contentRepository);
|
||||
return (configuration);
|
||||
}
|
||||
|
||||
private static List<Scenario> initializeScenarios(final Scenarios def, final ContentRepository contentRepository) {
|
||||
return def.getScenario().stream().map(s -> initialize(s, contentRepository)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private ContentRepository buildContentRepository() {
|
||||
return new ContentRepository(getProcessor(), getScenarioRepository());
|
||||
private ResolvingConfigurationStrategy getResolvingConfigurationStrategy() {
|
||||
if (this.resolvingConfigurationStrategy != null) {
|
||||
log.info("Custom resolving strategy supplied. Please take care of xml security!");
|
||||
return this.resolvingConfigurationStrategy;
|
||||
}
|
||||
log.info("Using resolving strategy {}", this.resolvingMode);
|
||||
return this.resolvingMode.getStrategy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContentRepository getContentRepository() {
|
||||
return buildContentRepository();
|
||||
}
|
||||
|
||||
private Scenarios loadScenarios() {
|
||||
private Scenarios loadScenarios(final Schema scenarioSchema, final Processor processor) {
|
||||
final ConversionService conversionService = new ConversionService();
|
||||
checkVersion(this.scenarioDefinition);
|
||||
checkVersion(this.scenarioDefinition, processor);
|
||||
log.info("Loading scenarios from {}", this.scenarioDefinition);
|
||||
final CollectingErrorEventHandler handler = new CollectingErrorEventHandler();
|
||||
final Scenarios scenarios = conversionService.readXml(this.scenarioDefinition, Scenarios.class,
|
||||
getContentRepository().getScenarioSchema(), handler);
|
||||
final Scenarios scenarios = conversionService.readXml(this.scenarioDefinition, Scenarios.class, scenarioSchema, handler);
|
||||
if (!handler.hasErrors()) {
|
||||
log.info("Loading scenario content from {}", this.scenarioRepository);
|
||||
log.info("Loading scenario content from {}", this.getScenarioRepository());
|
||||
} else {
|
||||
throw new IllegalStateException(
|
||||
String.format("Can not load scenarios from %s due to %s", getScenarioDefinition(), handler.getErrorDescription()));
|
||||
|
|
@ -152,27 +166,23 @@ public class LoadConfiguration extends BaseConfiguration {
|
|||
|
||||
private static Scenario initialize(final ScenarioType def, final ContentRepository repository) {
|
||||
final Scenario s = new Scenario(def);
|
||||
s.setSchema(repository.createSchema(def));
|
||||
s.setReportTransformation(repository.createReportTransformation(def));
|
||||
s.setMatchExecutable(repository.createMatchExecutable(def));
|
||||
s.setSchema(repository.createSchema(def));
|
||||
s.setSchematronValidations(repository.createSchematronTransformations(def));
|
||||
s.setReportTransformation(repository.createReportTransformation(def));
|
||||
if (def.getAcceptMatch() != null) {
|
||||
s.setAcceptExecutable(repository.createAccepptExecutable(def));
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAuthor() {
|
||||
return null;
|
||||
public ConfigurationLoader setResolvingMode(final ResolvingMode mode) {
|
||||
this.resolvingMode = mode;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDate() {
|
||||
return null;
|
||||
public ConfigurationLoader addParameter(final String name, final Object value) {
|
||||
this.parameters.put(name, value);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
package de.kosit.validationtool.config;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import de.kosit.validationtool.api.Configuration;
|
||||
import de.kosit.validationtool.impl.ContentRepository;
|
||||
import de.kosit.validationtool.impl.Scenario;
|
||||
|
||||
/**
|
||||
* Default implementation class for {@link Configuration}. This class contains all information to run a
|
||||
* {@link de.kosit.validationtool.impl.DefaultCheck}.
|
||||
*
|
||||
* @author Andreas Penski
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
@Setter
|
||||
public class DefaultConfiguration implements Configuration {
|
||||
|
||||
private final List<Scenario> scenarios;
|
||||
|
||||
private final Scenario fallbackScenario;
|
||||
|
||||
private ContentRepository contentRepository;
|
||||
|
||||
private String name;
|
||||
|
||||
private String author;
|
||||
|
||||
private String date;
|
||||
|
||||
public Map<String, Object> additionalParameters;
|
||||
}
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
package de.kosit.validationtool.config;
|
||||
|
||||
import java.net.URI;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import de.kosit.validationtool.impl.ContentRepository;
|
||||
import de.kosit.validationtool.impl.Scenario;
|
||||
import de.kosit.validationtool.impl.Scenario.Transformation;
|
||||
import de.kosit.validationtool.impl.model.Result;
|
||||
import de.kosit.validationtool.model.scenarios.CreateReportType;
|
||||
import de.kosit.validationtool.model.scenarios.ScenarioType;
|
||||
|
||||
/**
|
||||
* @author Andreas Penski
|
||||
*/
|
||||
public class FallbackBuilder implements Builder<Scenario> {
|
||||
|
||||
private final ReportBuilder internal = new ReportBuilder().name("fallback");
|
||||
|
||||
@Override
|
||||
public Result<Scenario, String> build(final ContentRepository repository) {
|
||||
final ScenarioType object = createObject();
|
||||
final Result<Pair<CreateReportType, Transformation>, String> build = this.internal.build(repository);
|
||||
final Result<Scenario, String> result;
|
||||
if (build.isValid()) {
|
||||
object.setCreateReport(build.getObject().getLeft());
|
||||
final Scenario s = new Scenario(object);
|
||||
s.setFallback(true);
|
||||
s.setReportTransformation(build.getObject().getRight());
|
||||
result = new Result<>(s);
|
||||
} else {
|
||||
result = new Result<>(build.getErrors());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static ScenarioType createObject() {
|
||||
final ScenarioType t = new ScenarioType();
|
||||
t.setName("Fallback-Scenario");
|
||||
t.setMatch("count(/)<0");
|
||||
// always reject
|
||||
t.setAcceptMatch("count(/)<0");
|
||||
return t;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifices a source for this report. This is either used to compile the report transformation or as documentation for
|
||||
* a precompiled tranformation.
|
||||
*
|
||||
* @param source the source
|
||||
* @return this
|
||||
*/
|
||||
public FallbackBuilder source(final String source) {
|
||||
this.internal.source(source);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifices a source for this report. This is either used to compile the report transformation or as documentation for
|
||||
* a precompiled tranformation.
|
||||
*
|
||||
* @param source the source
|
||||
* @return this
|
||||
*/
|
||||
public FallbackBuilder source(final URI source) {
|
||||
this.internal.source(source);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifices a source for this report. This is either used to compile the report transformation or as documentation for
|
||||
* a precompiled tranformation.
|
||||
*
|
||||
* @param source the source
|
||||
* @return this
|
||||
*/
|
||||
public FallbackBuilder source(final Path source) {
|
||||
this.internal.source(source);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the report source to a specific value.
|
||||
*
|
||||
* @param name the name
|
||||
* @return this
|
||||
*/
|
||||
public FallbackBuilder name(final String name) {
|
||||
this.internal.name(name);
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
116
src/main/java/de/kosit/validationtool/config/ReportBuilder.java
Normal file
116
src/main/java/de/kosit/validationtool/config/ReportBuilder.java
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
package de.kosit.validationtool.config;
|
||||
|
||||
import static org.apache.commons.lang3.ObjectUtils.isNotEmpty;
|
||||
|
||||
import java.net.URI;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.apache.commons.lang3.tuple.ImmutablePair;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import de.kosit.validationtool.impl.ContentRepository;
|
||||
import de.kosit.validationtool.impl.Scenario.Transformation;
|
||||
import de.kosit.validationtool.impl.model.Result;
|
||||
import de.kosit.validationtool.model.scenarios.CreateReportType;
|
||||
import de.kosit.validationtool.model.scenarios.ResourceType;
|
||||
|
||||
import net.sf.saxon.s9api.XsltExecutable;
|
||||
|
||||
/**
|
||||
* Builder style configuration for the report transformation.
|
||||
*
|
||||
* @author Andreas Penski
|
||||
*/
|
||||
@Slf4j
|
||||
public class ReportBuilder implements Builder<Pair<CreateReportType, Transformation>> {
|
||||
|
||||
private static final String DEFAULT_NAME = "manually created report";
|
||||
|
||||
private XsltExecutable executable;
|
||||
|
||||
private URI source;
|
||||
|
||||
private String name;
|
||||
|
||||
@Override
|
||||
public Result<Pair<CreateReportType, Transformation>, String> build(final ContentRepository repository) {
|
||||
if (this.executable == null && this.source == null) {
|
||||
return createError("Must supply source location and/or executable");
|
||||
}
|
||||
final CreateReportType object = createObject();
|
||||
Result<Pair<CreateReportType, Transformation>, String> result;
|
||||
|
||||
try {
|
||||
if (this.executable == null) {
|
||||
this.executable = repository.createTransformation(object.getResource()).getExecutable();
|
||||
}
|
||||
result = new Result<>(new ImmutablePair<>(object, new Transformation(this.executable, object.getResource())));
|
||||
} catch (final IllegalStateException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
result = createError(
|
||||
String.format("Can not create report configuration based on %s. Exception is %s", this.source, e.getMessage()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private CreateReportType createObject() {
|
||||
final CreateReportType o = new CreateReportType();
|
||||
final ResourceType r = new ResourceType();
|
||||
r.setLocation(this.source.toASCIIString());
|
||||
r.setName(isNotEmpty(this.name) ? this.name : DEFAULT_NAME);
|
||||
o.setResource(r);
|
||||
return o;
|
||||
}
|
||||
|
||||
private static Result<Pair<CreateReportType, Transformation>, String> createError(final String msg) {
|
||||
return new Result<>(null, Collections.singletonList(msg));
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifices a source for this report. This is either used to compile the report transformation or as documentation for
|
||||
* a precompiled tranformation.
|
||||
*
|
||||
* @param source the source
|
||||
* @return this
|
||||
*/
|
||||
public ReportBuilder source(final String source) {
|
||||
return source(URI.create(source));
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifices a source for this report. This is either used to compile the report transformation or as documentation for
|
||||
* a precompiled tranformation.
|
||||
*
|
||||
* @param source the source
|
||||
* @return this
|
||||
*/
|
||||
public ReportBuilder source(final URI source) {
|
||||
this.source = source;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifices a source for this report. This is either used to compile the report transformation or as documentation for
|
||||
* a precompiled tranformation.
|
||||
*
|
||||
* @param source the source
|
||||
* @return this
|
||||
*/
|
||||
public ReportBuilder source(final Path source) {
|
||||
return source(source.toUri());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the report source to a specific value.
|
||||
*
|
||||
* @param name the name
|
||||
* @return this
|
||||
*/
|
||||
public ReportBuilder name(final String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,72 +1,270 @@
|
|||
package de.kosit.validationtool.config;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.Collections;
|
||||
import static org.apache.commons.lang3.ObjectUtils.isNotEmpty;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.xml.validation.Schema;
|
||||
|
||||
import org.w3c.dom.ls.LSResourceResolver;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import de.kosit.validationtool.impl.ContentRepository;
|
||||
import de.kosit.validationtool.impl.ObjectFactory;
|
||||
import de.kosit.validationtool.impl.Scenario;
|
||||
import de.kosit.validationtool.impl.Scenario.Transformation;
|
||||
import de.kosit.validationtool.impl.model.Result;
|
||||
import de.kosit.validationtool.model.scenarios.CreateReportType;
|
||||
import de.kosit.validationtool.model.scenarios.DescriptionType;
|
||||
import de.kosit.validationtool.model.scenarios.NamespaceType;
|
||||
import de.kosit.validationtool.model.scenarios.ObjectFactory;
|
||||
import de.kosit.validationtool.model.scenarios.ScenarioType;
|
||||
import de.kosit.validationtool.model.scenarios.ValidateWithSchematron;
|
||||
import de.kosit.validationtool.model.scenarios.ValidateWithXmlSchema;
|
||||
|
||||
import net.sf.saxon.s9api.XsltExecutable;
|
||||
import net.sf.saxon.s9api.XPathExecutable;
|
||||
|
||||
/**
|
||||
* Builder for {@link Scenario} configuration.
|
||||
*
|
||||
* @author Andreas Penski
|
||||
*/
|
||||
public class ScenarioBuilder {
|
||||
@RequiredArgsConstructor
|
||||
public class ScenarioBuilder implements Builder<Scenario> {
|
||||
|
||||
private final ScenarioType scenario;
|
||||
private static int nameCount = 0;
|
||||
|
||||
private final ContentRepository contentRepository = new ContentRepository(ObjectFactory.createProcessor(), null);
|
||||
private static final String DEFAULT_DESCRIPTION = "Dieses Scenario wurde per API erstellt";
|
||||
|
||||
ScenarioBuilder(final String name) {
|
||||
this.scenario = new ScenarioType();
|
||||
this.scenario.setName(name);
|
||||
private final Map<String, String> namespaces = new HashMap<>();
|
||||
|
||||
private final XPathBuilder matchConfig = new XPathBuilder();
|
||||
|
||||
private final XPathBuilder acceptConfig = new XPathBuilder();
|
||||
|
||||
@Getter(AccessLevel.PACKAGE)
|
||||
private final String name;
|
||||
|
||||
private SchemaBuilder schemaBuilder;
|
||||
|
||||
private final List<SchematronBuilder> schematronBuilders = new ArrayList<>();
|
||||
|
||||
private ReportBuilder reportBuilder;
|
||||
|
||||
private String description;
|
||||
|
||||
@Override
|
||||
public Result<Scenario, String> build(final ContentRepository repository) {
|
||||
final List<String> errors = new ArrayList<>();
|
||||
final Scenario scenario = new Scenario(createType());
|
||||
buildMatch(repository, errors, scenario);
|
||||
buildSchema(repository, errors, scenario);
|
||||
buildSchematron(repository, errors, scenario);
|
||||
buildReport(repository, errors, scenario);
|
||||
buildAccept(repository, errors, scenario);
|
||||
buildNamespaces(scenario);
|
||||
return new Result<>(scenario, errors);
|
||||
}
|
||||
|
||||
public ScenarioBuilder matches(final String xpath) {
|
||||
return matches(xpath, Collections.emptyMap());
|
||||
}
|
||||
|
||||
private ScenarioBuilder matches(final String xpath, final Map<String, String> namespaces) {
|
||||
// final XPathExecutable matchExecutable = this.contentRepository.createXPath(xpath, namespaces);
|
||||
// this.scenario.setMatchExecutable(matchExecutable);
|
||||
// this.scenario.setMatch(xpath);
|
||||
// if (namespaces != null) {
|
||||
// this.scenario.getNamespace().addAll(namespaces.entrySet().stream().map(e -> {
|
||||
// NamespaceType t = new NamespaceType();
|
||||
// t.setPrefix(e.getKey());
|
||||
// t.setValue(e.getValue());
|
||||
// return t;
|
||||
// }).collect(Collectors.toList()));
|
||||
// } else {
|
||||
// this.scenario.getNamespace().clear();
|
||||
// }
|
||||
/**
|
||||
* Add a preconfiguration {@link XPathExecutable} to match the scenario
|
||||
*
|
||||
* @param executable the xpath executable
|
||||
* @return this
|
||||
*/
|
||||
public ScenarioBuilder match(final XPathExecutable executable) {
|
||||
this.matchConfig.setExecutable(executable);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ScenarioBuilder schemaValidation(final Schema schema) {
|
||||
/**
|
||||
* Add an xpath expression to match the scenario. You can leverage declared namespaces.
|
||||
*
|
||||
* @param xpath the expression
|
||||
* @return this
|
||||
*/
|
||||
public ScenarioBuilder match(final String xpath) {
|
||||
this.matchConfig.setXpath(xpath);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ScenarioBuilder schemaValidation(final URL url) {
|
||||
return schemalidation(url, null);
|
||||
}
|
||||
|
||||
private ScenarioBuilder schemalidation(final URL url, final LSResourceResolver resolver) {
|
||||
/**
|
||||
* Declare a namespace to use for match and accept configurations.
|
||||
*
|
||||
* @param prefix the prefix to use
|
||||
* @param uri the uri of this namespace
|
||||
* @return this
|
||||
*/
|
||||
public ScenarioBuilder declareNamespace(final String prefix, final String uri) {
|
||||
this.namespaces.put(prefix, uri);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ScenarioBuilder addSchematronValidation(final XsltExecutable executable) {
|
||||
/**
|
||||
* Add a preconfiguration {@link XPathExecutable} to compute acceptance for the scenario
|
||||
*
|
||||
* @param executable the xpath executable
|
||||
* @return this
|
||||
*/
|
||||
public ScenarioBuilder acceptWith(final XPathExecutable executable) {
|
||||
this.acceptConfig.setExecutable(executable);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ScenarioBuilder withReportGenerator(final XsltExecutable executable) {
|
||||
/**
|
||||
* Add an xpath expression to compute acceptance for the scenario. You can leverage declared namespaces.
|
||||
*
|
||||
* @param acceptXpath the xpath expresison
|
||||
* @return this
|
||||
*/
|
||||
public ScenarioBuilder acceptWith(final String acceptXpath) {
|
||||
this.acceptConfig.setXpath(acceptXpath);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a schematron validation configuration for this scenario.
|
||||
*
|
||||
* @param schematron the schematron configuration
|
||||
* @return this
|
||||
*/
|
||||
public ScenarioBuilder validate(final SchematronBuilder schematron) {
|
||||
if (schematron != null) {
|
||||
this.schematronBuilders.add(schematron);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate matching {@link de.kosit.validationtool.api.Input Inputs} with the specified schema configuration.
|
||||
*
|
||||
* @param schema the schema configuration
|
||||
* @return this
|
||||
*/
|
||||
public ScenarioBuilder validate(final SchemaBuilder schema) {
|
||||
this.schemaBuilder = schema;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add description for this scenario. This is part of the
|
||||
* {@link de.kosit.validationtool.model.reportInput.CreateReportInput} configuration and can be used while creating the
|
||||
* report
|
||||
*
|
||||
* @param description the description
|
||||
* @return this
|
||||
*/
|
||||
public ScenarioBuilder description(final String description) {
|
||||
this.description = description;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a configuration for generating the final report for the {@link de.kosit.validationtool.api.Input}.
|
||||
*
|
||||
* @param reportBuilder the report configuration
|
||||
* @return this
|
||||
*/
|
||||
public ScenarioBuilder with(final ReportBuilder reportBuilder) {
|
||||
this.reportBuilder = reportBuilder;
|
||||
return this;
|
||||
}
|
||||
|
||||
private static String generateName() {
|
||||
return "manually created scenario " + nameCount++;
|
||||
}
|
||||
|
||||
private void buildNamespaces(final Scenario scenario) {
|
||||
this.namespaces.putAll(this.acceptConfig.getNamespaces());
|
||||
this.namespaces.putAll(this.matchConfig.getNamespaces());
|
||||
final List<NamespaceType> all = this.namespaces.entrySet().stream().map(e -> {
|
||||
final NamespaceType n = new NamespaceType();
|
||||
n.setPrefix(e.getKey());
|
||||
n.setValue(e.getValue());
|
||||
return n;
|
||||
}).collect(Collectors.toList());
|
||||
scenario.getConfiguration().getNamespace().addAll(all);
|
||||
}
|
||||
|
||||
private void buildMatch(final ContentRepository repository, final List<String> errors, final Scenario scenario) {
|
||||
this.matchConfig.setNamespaces(this.namespaces);
|
||||
final Result<XPathExecutable, String> result = this.matchConfig.build(repository);
|
||||
if (result.isValid()) {
|
||||
scenario.setMatchExecutable(result.getObject());
|
||||
scenario.getConfiguration().setMatch(this.matchConfig.getXPath());
|
||||
this.namespaces.putAll(this.matchConfig.getNamespaces());
|
||||
} else {
|
||||
errors.addAll(result.getErrors());
|
||||
}
|
||||
}
|
||||
|
||||
private void buildAccept(final ContentRepository repository, final List<String> errors, final Scenario scenario) {
|
||||
this.acceptConfig.setNamespaces(this.namespaces);
|
||||
final Result<XPathExecutable, String> result = this.acceptConfig.build(repository);
|
||||
if (result.isValid()) {
|
||||
scenario.setAcceptExecutable(result.getObject());
|
||||
scenario.getConfiguration().setAcceptMatch(this.acceptConfig.getXPath());
|
||||
this.namespaces.putAll(this.acceptConfig.getNamespaces());
|
||||
} else {
|
||||
errors.addAll(result.getErrors());
|
||||
}
|
||||
}
|
||||
|
||||
private void buildReport(final ContentRepository repository, final List<String> errors, final Scenario scenario) {
|
||||
if (this.reportBuilder == null) {
|
||||
errors.add("Must supply report configuration");
|
||||
} else {
|
||||
final Result<Pair<CreateReportType, Transformation>, String> result = this.reportBuilder.build(repository);
|
||||
if (result.isValid()) {
|
||||
scenario.setReportTransformation(result.getObject().getRight());
|
||||
scenario.getConfiguration().setCreateReport(result.getObject().getLeft());
|
||||
} else {
|
||||
errors.addAll(result.getErrors());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void buildSchematron(final ContentRepository repository, final List<String> errors, final Scenario scenario) {
|
||||
this.schematronBuilders.forEach(e -> {
|
||||
final Result<Pair<ValidateWithSchematron, Transformation>, String> result = e.build(repository);
|
||||
if (result.isValid()) {
|
||||
scenario.getConfiguration().getValidateWithSchematron().add(result.getObject().getLeft());
|
||||
scenario.getSchematronValidations().add(result.getObject().getRight());
|
||||
} else {
|
||||
errors.addAll(result.getErrors());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void buildSchema(final ContentRepository repository, final List<String> errors, final Scenario scenario) {
|
||||
if (this.schemaBuilder == null) {
|
||||
errors.add("Must supply schema for validation");
|
||||
} else {
|
||||
final Result<Pair<ValidateWithXmlSchema, Schema>, String> result = this.schemaBuilder.build(repository);
|
||||
if (result.isValid()) {
|
||||
scenario.setSchema(result.getObject().getRight());
|
||||
scenario.getConfiguration().setValidateWithXmlSchema(result.getObject().getLeft());
|
||||
} else {
|
||||
errors.addAll(result.getErrors());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ScenarioType createType() {
|
||||
final ScenarioType type = new ScenarioType();
|
||||
type.setName(isNotEmpty(this.name) ? this.name : generateName());
|
||||
final DescriptionType desc = new DescriptionType();
|
||||
desc.getPOrOlOrUl()
|
||||
.add(new ObjectFactory().createDescriptionTypeP(StringUtils.defaultIfBlank(this.description, DEFAULT_DESCRIPTION)));
|
||||
type.setDescription(desc);
|
||||
return type;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
121
src/main/java/de/kosit/validationtool/config/SchemaBuilder.java
Normal file
121
src/main/java/de/kosit/validationtool/config/SchemaBuilder.java
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
package de.kosit.validationtool.config;
|
||||
|
||||
import static org.apache.commons.lang3.ObjectUtils.isNotEmpty;
|
||||
|
||||
import java.net.URI;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collections;
|
||||
|
||||
import javax.xml.validation.Schema;
|
||||
|
||||
import org.apache.commons.lang3.tuple.ImmutablePair;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import de.kosit.validationtool.impl.ContentRepository;
|
||||
import de.kosit.validationtool.impl.model.Result;
|
||||
import de.kosit.validationtool.model.scenarios.ResourceType;
|
||||
import de.kosit.validationtool.model.scenarios.ValidateWithXmlSchema;
|
||||
|
||||
/**
|
||||
* Builder for Schema validation configuration.
|
||||
*
|
||||
* @author Andreas Penski
|
||||
*/
|
||||
@Slf4j
|
||||
public class SchemaBuilder implements Builder<Pair<ValidateWithXmlSchema, Schema>> {
|
||||
|
||||
private static final String DEFAULT_NAME = "manually configured";
|
||||
|
||||
private Schema schema;
|
||||
|
||||
private URI schemaLocation;
|
||||
|
||||
private String name;
|
||||
|
||||
@Override
|
||||
public Result<Pair<ValidateWithXmlSchema, Schema>, String> build(final ContentRepository repository) {
|
||||
if (this.schema == null && this.schemaLocation == null) {
|
||||
return createError("Must supply schema location and/or schema");
|
||||
}
|
||||
Result<Pair<ValidateWithXmlSchema, Schema>, String> result;
|
||||
try {
|
||||
if (this.schema == null) {
|
||||
this.schema = repository.createSchema(this.schemaLocation);
|
||||
}
|
||||
result = new Result<>(new ImmutablePair<>(createObject(), this.schema));
|
||||
} catch (final IllegalStateException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
result = createError(String.format("Can not create schema based %s. Exception is %s", this.schemaLocation, e.getMessage()));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private ValidateWithXmlSchema createObject() {
|
||||
final ValidateWithXmlSchema o = new ValidateWithXmlSchema();
|
||||
final ResourceType r = new ResourceType();
|
||||
r.setName(isNotEmpty(this.name) ? this.name : DEFAULT_NAME);
|
||||
r.setLocation(this.schemaLocation.toASCIIString());
|
||||
o.getResource().add(r);
|
||||
return o;
|
||||
}
|
||||
|
||||
private static Result<Pair<ValidateWithXmlSchema, Schema>, String> createError(final String msg) {
|
||||
return new Result<>(null, Collections.singletonList(msg));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a specific precompiled schema to check.
|
||||
*
|
||||
* @param schema the {@link Schema}
|
||||
* @return this
|
||||
*/
|
||||
public SchemaBuilder schema(final Schema schema) {
|
||||
this.schema = schema;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a specific schema location either to compile or to document the precompiled one .
|
||||
*
|
||||
* @param schemaLocation the schema location as uri
|
||||
* @return this
|
||||
*/
|
||||
public SchemaBuilder schemaLocation(final URI schemaLocation) {
|
||||
this.schemaLocation = schemaLocation;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a specific schema location either to compile or to document the precompiled one .
|
||||
*
|
||||
* @param schemaLocation the schema location as uri
|
||||
* @return this
|
||||
*/
|
||||
public SchemaBuilder schemaLocation(final String schemaLocation) {
|
||||
return schemaLocation(URI.create(schemaLocation));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a specific schema location either to compile or to document the precompiled one .
|
||||
*
|
||||
* @param schemaLocation the schema location as uri
|
||||
* @return this
|
||||
*/
|
||||
public SchemaBuilder schemaLocation(final Path schemaLocation) {
|
||||
return schemaLocation(schemaLocation.toUri());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a specific name to identify this schema.
|
||||
*
|
||||
* @param name the name of the schema
|
||||
* @return this
|
||||
*/
|
||||
public SchemaBuilder name(final String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
package de.kosit.validationtool.config;
|
||||
|
||||
import static org.apache.commons.lang3.ObjectUtils.isNotEmpty;
|
||||
|
||||
import java.net.URI;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.apache.commons.lang3.tuple.ImmutablePair;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import de.kosit.validationtool.impl.ContentRepository;
|
||||
import de.kosit.validationtool.impl.Scenario.Transformation;
|
||||
import de.kosit.validationtool.impl.model.Result;
|
||||
import de.kosit.validationtool.model.scenarios.ResourceType;
|
||||
import de.kosit.validationtool.model.scenarios.ValidateWithSchematron;
|
||||
|
||||
import net.sf.saxon.s9api.XsltExecutable;
|
||||
|
||||
/**
|
||||
* Builder for schematron validation configuration.
|
||||
*
|
||||
* @author Andreas Penski
|
||||
*/
|
||||
@Slf4j
|
||||
public class SchematronBuilder implements Builder<Pair<ValidateWithSchematron, Transformation>> {
|
||||
|
||||
private static final String DEFAULT_NAME = "manually configured";
|
||||
|
||||
private XsltExecutable executable;
|
||||
|
||||
private URI source;
|
||||
|
||||
private String name;
|
||||
|
||||
@Override
|
||||
public Result<Pair<ValidateWithSchematron, Transformation>, String> build(final ContentRepository repository) {
|
||||
if (this.executable == null && this.source == null) {
|
||||
return createError("Must supply source location and/or executable");
|
||||
}
|
||||
final ValidateWithSchematron object = createObject();
|
||||
Result<Pair<ValidateWithSchematron, Transformation>, String> result;
|
||||
|
||||
try {
|
||||
if (this.executable == null) {
|
||||
this.executable = repository.createSchematronTransformation(object).getExecutable();
|
||||
}
|
||||
result = new Result<>(new ImmutablePair<>(object, new Transformation(this.executable, object.getResource())));
|
||||
} catch (final IllegalStateException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
result = createError(
|
||||
String.format("Can not create schematron configuration based on %s. Exception is %s", this.source, e.getMessage()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private ValidateWithSchematron createObject() {
|
||||
final ValidateWithSchematron o = new ValidateWithSchematron();
|
||||
final ResourceType r = new ResourceType();
|
||||
r.setLocation(this.source.toASCIIString());
|
||||
r.setName(isNotEmpty(this.name) ? this.name : DEFAULT_NAME);
|
||||
o.setResource(r);
|
||||
return o;
|
||||
}
|
||||
|
||||
private static Result<Pair<ValidateWithSchematron, Transformation>, String> createError(final String msg) {
|
||||
return new Result<>(null, Collections.singletonList(msg));
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifices a source for this schematron validation. This is either used to compile the schematron transformation or
|
||||
* as documentation for a precompiled tranformation.
|
||||
*
|
||||
* @param source the source
|
||||
* @return this
|
||||
*/
|
||||
public SchematronBuilder source(final String source) {
|
||||
return source(URI.create(source));
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifices a source for this schematron validation. This is either used to compile the schematron transformation or
|
||||
* as documentation for a precompiled tranformation.
|
||||
*
|
||||
* @param source the source
|
||||
* @return this
|
||||
*/
|
||||
public SchematronBuilder source(final URI source) {
|
||||
this.source = source;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifices a source for this schematron validation. This is either used to compile the schematron transformation or
|
||||
* as documentation for a precompiled tranformation.
|
||||
*
|
||||
* @param source the source
|
||||
* @return this
|
||||
*/
|
||||
public SchematronBuilder source(final Path source) {
|
||||
return source(source.toUri());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the schematron source to a specific value.
|
||||
*
|
||||
* @param name the name
|
||||
* @return this
|
||||
*/
|
||||
public SchematronBuilder name(final String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
package de.kosit.validationtool.config;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import de.kosit.validationtool.impl.ContentRepository;
|
||||
import de.kosit.validationtool.impl.model.Result;
|
||||
|
||||
import net.sf.saxon.s9api.XPathExecutable;
|
||||
|
||||
/**
|
||||
* Internal class to represent xpath configuration.
|
||||
*
|
||||
* @author Andreas Penski
|
||||
*/
|
||||
@Data
|
||||
class XPathBuilder implements Builder<XPathExecutable> {
|
||||
|
||||
private static final String[] IGNORED_PREFIXES = new String[] { "xsd" };
|
||||
|
||||
private String xpath;
|
||||
|
||||
private XPathExecutable executable;
|
||||
|
||||
@Setter(AccessLevel.PACKAGE)
|
||||
@Getter(AccessLevel.PACKAGE)
|
||||
private Map<String, String> namespaces;
|
||||
|
||||
/**
|
||||
* Returns the xpath expression.
|
||||
*
|
||||
* @return xpath expression
|
||||
*/
|
||||
public String getXPath() {
|
||||
return this.xpath == null && this.executable != null ? this.executable.getUnderlyingExpression().getInternalExpression().toString()
|
||||
: this.xpath;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<XPathExecutable, String> build(final ContentRepository repository) {
|
||||
if (this.executable == null && this.xpath == null) {
|
||||
return createError("No configuration for xpath expression found");
|
||||
}
|
||||
if (this.executable == null) {
|
||||
this.executable = repository.createXPath(this.xpath, this.namespaces);
|
||||
} else {
|
||||
this.xpath = extractExpression();
|
||||
this.namespaces = extractNamespaces();
|
||||
}
|
||||
return new Result<>(this.executable);
|
||||
}
|
||||
|
||||
private Map<String, String> extractNamespaces() {
|
||||
final Map<String, String> ns = new HashMap<>();
|
||||
final Iterator<String> iterator = this.executable.getUnderlyingExpression().getInternalExpression().getRetainedStaticContext()
|
||||
.iteratePrefixes();
|
||||
final Iterable<String> iterable = () -> iterator;
|
||||
StreamSupport.stream(iterable.spliterator(), false).filter(e -> !ArrayUtils.contains(IGNORED_PREFIXES, e)).forEach(e -> {
|
||||
ns.put(e,
|
||||
this.executable.getUnderlyingExpression().getInternalExpression().getRetainedStaticContext().getURIForPrefix(e, false));
|
||||
});
|
||||
return ns;
|
||||
}
|
||||
|
||||
private String extractExpression() {
|
||||
return this.executable.getUnderlyingExpression().getInternalExpression().toString();
|
||||
}
|
||||
|
||||
private static Result<XPathExecutable, String> createError(final String msg) {
|
||||
return new Result<>(null, Collections.singletonList(msg));
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue