mirror of
https://github.com/itplr-kosit/validator.git
synced 2026-05-25 16:55:39 +00:00
Initial Implementation
This commit is contained in:
parent
2950785e25
commit
beeb104007
98 changed files with 29308 additions and 0 deletions
37
src/main/assembly/standalone-assembly.xml
Normal file
37
src/main/assembly/standalone-assembly.xml
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
<!--
|
||||
~ 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.
|
||||
-->
|
||||
|
||||
<assembly>
|
||||
<id>standalone</id>
|
||||
<formats>
|
||||
<format>jar</format>
|
||||
</formats>
|
||||
<includeBaseDirectory>false</includeBaseDirectory>
|
||||
<dependencySets>
|
||||
<dependencySet>
|
||||
<unpack>true</unpack>
|
||||
<scope>runtime</scope>
|
||||
</dependencySet>
|
||||
</dependencySets>
|
||||
<fileSets>
|
||||
<fileSet>
|
||||
<directory>${project.build.outputDirectory}</directory>
|
||||
</fileSet>
|
||||
</fileSets>
|
||||
</assembly>
|
||||
53
src/main/java/de/kosit/validationtool/api/Check.java
Normal file
53
src/main/java/de/kosit/validationtool/api/Check.java
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* 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.api;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.w3c.dom.Document;
|
||||
|
||||
/**
|
||||
* Zentrale Schnittstellendefinition für das Prüf-Tool.
|
||||
*
|
||||
* @author Andreas Penski
|
||||
*/
|
||||
public interface Check {
|
||||
|
||||
/**
|
||||
* Führt die konfigurierte Prüfung für die übergebene Resource aus.
|
||||
*
|
||||
* @param input die Resource / XML-Datei, die geprüft werden soll.
|
||||
* @return ein Ergebnis-{@link Document}
|
||||
*/
|
||||
Document check(Input input);
|
||||
|
||||
|
||||
/**
|
||||
* Führt eine Prüfung im Batch-Mode durch. Die Default-Implementierung führt die Prüfung sequentiell aus.
|
||||
*
|
||||
* @param input die Eingabe
|
||||
* @return Liste mit Ergebnis-Dokumenten
|
||||
*/
|
||||
default List<Document> check(List<Input> input) {
|
||||
return input.stream().map(i -> check(i)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* 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.api;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
/**
|
||||
* Zentrale Konfigration einer Prüf-Instanz.
|
||||
*
|
||||
* @author Andreas Penski
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class CheckConfiguration {
|
||||
|
||||
/**
|
||||
* URL, die auf die scenerio.xml Datei zeigt.
|
||||
*/
|
||||
private final URI scenarioDefinition;
|
||||
|
||||
/**
|
||||
* Root-Ordner mit den von den einzelnen Szenarien benötigten Dateien
|
||||
*/
|
||||
private URI scenarioRepository;
|
||||
|
||||
|
||||
/**
|
||||
* Liefert das Repository mit den Artefakten der einzelnen Szenarien.
|
||||
*
|
||||
* @return uri die durch entsprechende resolver aufgelöst werden kann
|
||||
*/
|
||||
public URI getScenarioRepository() {
|
||||
if (scenarioRepository == null) {
|
||||
scenarioRepository = createDefaultRepository();
|
||||
}
|
||||
return scenarioRepository;
|
||||
}
|
||||
|
||||
private URI createDefaultRepository() {
|
||||
log.info("Creating default scenario repository (alongside scenario definition)");
|
||||
return scenarioDefinition.resolve(".");
|
||||
}
|
||||
|
||||
}
|
||||
45
src/main/java/de/kosit/validationtool/api/Input.java
Normal file
45
src/main/java/de/kosit/validationtool/api/Input.java
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* 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.api;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
/**
|
||||
* Eine Datei in eingelesener Form.
|
||||
*
|
||||
* @author apenski
|
||||
*/
|
||||
@Getter
|
||||
@RequiredArgsConstructor (access = AccessLevel.PACKAGE)
|
||||
@AllArgsConstructor (access = AccessLevel.PACKAGE)
|
||||
public class Input {
|
||||
|
||||
private final byte[] content;
|
||||
|
||||
private final String name;
|
||||
|
||||
private byte[] hashCode;
|
||||
|
||||
private String digestAlgorithm;
|
||||
|
||||
}
|
||||
244
src/main/java/de/kosit/validationtool/api/InputFactory.java
Normal file
244
src/main/java/de/kosit/validationtool/api/InputFactory.java
Normal file
|
|
@ -0,0 +1,244 @@
|
|||
/*
|
||||
* 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.api;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isNotEmpty;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.security.DigestInputStream;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* Service zum Einlesen des Test-Objekts in den Speicher. Beim Einlesen wird gleichzeitig eine Prüfsumme ermittelt und
|
||||
* mit dem Ergebnis mitgeführt.
|
||||
*
|
||||
* @author Andreas Penski
|
||||
*/
|
||||
@Slf4j
|
||||
public class InputFactory {
|
||||
|
||||
static final String DEFAULT_ALGORITH = "SHA-256";
|
||||
|
||||
private static final int EOF = -1;
|
||||
|
||||
private static final int DEFAULT_BUFFER_SIZE = 4096;
|
||||
|
||||
public static final String MESSAGE_OPEN_STREAM_ERROR = "Can not open stream from";
|
||||
|
||||
@Getter
|
||||
private final String algorithm;
|
||||
|
||||
InputFactory() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
InputFactory(String specifiedAlgorithm) {
|
||||
this.algorithm = isNotEmpty(specifiedAlgorithm) ? specifiedAlgorithm : DEFAULT_ALGORITH;
|
||||
createDigest();
|
||||
}
|
||||
|
||||
/**
|
||||
* Liest einen Prüfling von dem übergebenen Pfad. Es wird der Default-Prüfsummenalgorithmus zur Ermittlung der Prüfsumme
|
||||
* genutzt.
|
||||
*
|
||||
* @param path der Prüflings
|
||||
* @return ein Prüf-Eingabe-Objekt
|
||||
*/
|
||||
public static Input read(Path path) {
|
||||
return read(path, DEFAULT_ALGORITH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Liest einen Prüfling von der übergebenen URL. Es wird ein definierter Algorithmis zur Ermittlung der Prüfsumme
|
||||
* genutzt.
|
||||
*
|
||||
* @param path der Prüflings
|
||||
* @param digestAlgorithm der Prüfsummenalgorithmus
|
||||
* @return ein Prüf-Eingabe-Objekt
|
||||
*/
|
||||
public static Input read(Path path, String digestAlgorithm) {
|
||||
checkNull(path);
|
||||
try ( InputStream stream = Files.newInputStream(path) ) {
|
||||
return read(stream, path.toString(), digestAlgorithm);
|
||||
} catch (IOException e) {
|
||||
throw new IllegalArgumentException(MESSAGE_OPEN_STREAM_ERROR + path, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Liest einen Prüfling von der übergebenen Datei. Es wird der Default-Prüfsummenalgorithmus zur Ermittlung der
|
||||
* Prüfsumme genutzt.
|
||||
*
|
||||
* @param file der Prüflings
|
||||
* @return ein Prüf-Eingabe-Objekt
|
||||
*/
|
||||
public static Input read(File file) {
|
||||
return read(file, DEFAULT_ALGORITH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Liest einen Prüfling von der übergebenen URL. Es wird der Default-Prüfsummenalgorithmus zur Ermittlung der Prüfsumme
|
||||
* genutzt.
|
||||
*
|
||||
* @param url URL des Prüflings
|
||||
* @return ein Prüf-Eingabe-Objekt
|
||||
*/
|
||||
public static Input read(URL url) {
|
||||
return read(url, DEFAULT_ALGORITH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Liest einen Prüfling von der übergebenen URL. Es wird ein definierter Algorithmis zur Ermittlung der Prüfsumme
|
||||
* genutzt.
|
||||
*
|
||||
* @param url URL des Prüflings
|
||||
* @param digestAlgorithm der Prüfsummenalgorithmus
|
||||
* @return ein Prüf-Eingabe-Objekt
|
||||
*/
|
||||
public static Input read(URL url, String digestAlgorithm) {
|
||||
checkNull(url);
|
||||
try {
|
||||
return read(url.openStream(), url.getFile(), digestAlgorithm);
|
||||
} catch (IOException e) {
|
||||
throw new IllegalArgumentException(MESSAGE_OPEN_STREAM_ERROR + url, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Liest einen Prüfling von der übergebenen URL. Es wird ein definierter Algorithmis zur Ermittlung der Prüfsumme
|
||||
* genutzt.
|
||||
*
|
||||
* @param file der Prüflings
|
||||
* @param digestAlgorithm der Prüfsummenalgorithmus
|
||||
* @return ein Prüf-Eingabe-Objekt
|
||||
*/
|
||||
public static Input read(File file, String digestAlgorithm) {
|
||||
checkNull(file);
|
||||
try {
|
||||
return read(file.toURI().toURL(), digestAlgorithm);
|
||||
} catch (IOException e) {
|
||||
throw new IllegalArgumentException(MESSAGE_OPEN_STREAM_ERROR + file, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Liest einen Prüfling von der übergebenen byte-Sequenz. Es wird ein definierter Algorithmis zur Ermittlung der
|
||||
* Prüfsumme genutzt.
|
||||
*
|
||||
* @param input URL des Prüflings
|
||||
* @return ein Prüf-Eingabe-Objekt
|
||||
*/
|
||||
public static Input read(byte[] input, String name) {
|
||||
checkNull(input);
|
||||
return read(input, name, DEFAULT_ALGORITH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Liest einen Prüfling von der übergebenen byte-Sequenz. Es wird ein definierter Algorithmis zur Ermittlung der
|
||||
* Prüfsumme genutzt.
|
||||
*
|
||||
* @param input URL des Prüflings
|
||||
* @param digestAlgorithm der Prüfsummenalgorithmus
|
||||
* @return ein Prüf-Eingabe-Objekt
|
||||
*/
|
||||
public static Input read(byte[] input, String name, String digestAlgorithm) {
|
||||
checkNull(input);
|
||||
return read(new ByteArrayInputStream(input), name, digestAlgorithm);
|
||||
}
|
||||
|
||||
private static void checkNull(Object input) {
|
||||
if (input == null) {
|
||||
throw new IllegalArgumentException("Input can not be null");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Liest einen Prüfling vom übergebenen {@link InputStream}.
|
||||
*
|
||||
* @param inputStream der {@link InputStream}
|
||||
* @param name der Name/Bezeichner des Prüflings
|
||||
* @return einen Prüfling in eingelesener Form
|
||||
*/
|
||||
public static Input read(InputStream inputStream, String name) {
|
||||
return read(inputStream, name, DEFAULT_ALGORITH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Liest einen Prüfling vom übergebenen {@link InputStream}.
|
||||
*
|
||||
* @param inputStream der {@link InputStream}
|
||||
* @param name der Name/Bezeichner des Prüflings
|
||||
* @param digestAlgorithm der Prüfsummenalgorithmus
|
||||
* @return einen Prüfling in eingelesener Form
|
||||
*/
|
||||
public static Input read(InputStream inputStream, String name, String digestAlgorithm) {
|
||||
return new InputFactory(digestAlgorithm).readStream(inputStream, name);
|
||||
}
|
||||
|
||||
private Input readStream(InputStream inputStream, String name) {
|
||||
if (StringUtils.isNotBlank(name)) {
|
||||
log.debug("Generating hashcode for {} using {} algorithm", name, getAlgorithm());
|
||||
MessageDigest digest = createDigest();
|
||||
byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
|
||||
try ( BufferedInputStream bis = new BufferedInputStream(inputStream);
|
||||
DigestInputStream dis = new DigestInputStream(bis, digest);
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream() ) {
|
||||
|
||||
// read the file and update the hash calculation
|
||||
int n;
|
||||
while (EOF != (n = dis.read(buffer))) {
|
||||
out.write(buffer, 0, n);
|
||||
}
|
||||
// get the hash value as byte array
|
||||
byte[] hash = digest.digest();
|
||||
log.debug("Generated hashcode for {} is {}", name, DatatypeConverter.printHexBinary(hash));
|
||||
out.flush();
|
||||
return new Input(out.toByteArray(), name, hash, digest.getAlgorithm());
|
||||
} catch (IOException e) {
|
||||
throw new IllegalArgumentException(MESSAGE_OPEN_STREAM_ERROR + name, e);
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException("Must supply a valid name/identifier for the input");
|
||||
}
|
||||
}
|
||||
|
||||
private MessageDigest createDigest() {
|
||||
try {
|
||||
MessageDigest digest;
|
||||
digest = MessageDigest.getInstance(getAlgorithm());
|
||||
return digest;
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
// should not happen
|
||||
throw new IllegalStateException(String.format("Specified method %s is not available", getAlgorithm()), e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,132 @@
|
|||
/*
|
||||
* 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.cmd;
|
||||
|
||||
import de.kosit.validationtool.cmd.assertions.AssertionType;
|
||||
import de.kosit.validationtool.cmd.assertions.Assertions;
|
||||
import de.kosit.validationtool.impl.model.Result;
|
||||
import de.kosit.validationtool.impl.tasks.CheckAction;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.sf.saxon.s9api.*;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.w3c.dom.Document;
|
||||
|
||||
import javax.xml.transform.dom.DOMSource;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Überprüft den Report mittels bereitgestellter Assertions. Diese {@link CheckAction} dient der Überprüfung der von der
|
||||
* KoSIT bereitgestellten Prüfszenarien und den darin enthaltenen Artefakten.
|
||||
*
|
||||
* @author Andreas Penski
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class CheckAssertionAction implements CheckAction {
|
||||
|
||||
private final Assertions assertions;
|
||||
|
||||
@Getter(AccessLevel.PRIVATE)
|
||||
private final Processor processor;
|
||||
|
||||
private Map<String, List<AssertionType>> mappedAssertions;
|
||||
|
||||
private static boolean matches(String key, String name) {
|
||||
return key.startsWith(name) || (name + ".xml").endsWith(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void check(Bag results) {
|
||||
log.info("Checking assertions for {}", results.getInput().getName());
|
||||
final List<AssertionType> toCheck = findAssertions(results.getName());
|
||||
final List<String> errors = new ArrayList<>();
|
||||
if (toCheck != null && !toCheck.isEmpty()) {
|
||||
final XdmNode node = loadDocument(results.getReport());
|
||||
toCheck.forEach(a -> {
|
||||
if (!check(node, a)) {
|
||||
log.error("Assertion mismatch: {}", a.getValue());
|
||||
errors.add(a.getValue());
|
||||
}
|
||||
});
|
||||
if (errors.isEmpty()) {
|
||||
log.info("{} assertions successfully verified for {}", toCheck.size(), results.getName());
|
||||
} else {
|
||||
log.warn("{} assertion of {} failed while checking {}", errors.size(), toCheck.size(), results.getName());
|
||||
}
|
||||
results.setAssertionResult(new Result<>(toCheck.size(), errors));
|
||||
} else {
|
||||
log.warn("Can not find assertions for {}", results.getName());
|
||||
}
|
||||
}
|
||||
|
||||
private List<AssertionType> findAssertions(String name) {
|
||||
return getMapped().entrySet().stream().filter(e -> matches(e.getKey(), name)).map(Map.Entry::getValue).findFirst().orElse(null);
|
||||
}
|
||||
|
||||
private XdmNode loadDocument(Document d) {
|
||||
DocumentBuilder documentBuilder = getProcessor().newDocumentBuilder();
|
||||
try {
|
||||
return documentBuilder.build(new DOMSource(d));
|
||||
} catch (SaxonApiException e) {
|
||||
log.error("Can not load result document. Therefore can not run defined assertions", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean check(XdmNode document, AssertionType assertion) {
|
||||
try {
|
||||
final XPathSelector selector = createSelector(assertion);
|
||||
selector.setContextItem(document);
|
||||
return selector.effectiveBooleanValue();
|
||||
} catch (SaxonApiException e) {
|
||||
log.error("Error evaluating assertion {} for {}", assertion.getTest(), assertion.getReportDoc(), e);
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
private XPathSelector createSelector(AssertionType assertion) throws SaxonApiException {
|
||||
try {
|
||||
final XPathCompiler compiler = getProcessor().newXPathCompiler();
|
||||
assertions.getNamespace().forEach(ns -> compiler.declareNamespace(ns.getPrefix(), ns.getValue()));
|
||||
return compiler.compile(assertion.getTest()).load();
|
||||
} catch (SaxonApiException e) {
|
||||
throw new IllegalStateException(String.format("Can not compile xpath match expression '%s'",
|
||||
StringUtils.isNotBlank(assertion.getTest()) ? assertion.getTest() : "EMPTY EXPRESSION"), e);
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, List<AssertionType>> getMapped() {
|
||||
if (mappedAssertions == null) {
|
||||
mappedAssertions = new HashMap<>();
|
||||
for (AssertionType assertionType : assertions.getAssertion()) {
|
||||
List<AssertionType> list = mappedAssertions.computeIfAbsent(assertionType.getReportDoc(), k -> new ArrayList<>());
|
||||
list.add(assertionType);
|
||||
}
|
||||
}
|
||||
return mappedAssertions;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,290 @@
|
|||
/*
|
||||
* 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.cmd;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.cli.*;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import de.kosit.validationtool.api.CheckConfiguration;
|
||||
import de.kosit.validationtool.api.Input;
|
||||
import de.kosit.validationtool.api.InputFactory;
|
||||
import de.kosit.validationtool.cmd.assertions.Assertions;
|
||||
import de.kosit.validationtool.impl.ConversionService;
|
||||
import de.kosit.validationtool.impl.ObjectFactory;
|
||||
|
||||
/**
|
||||
* Commandline Version des Prüftools. Parsed die Kommandozeile und führt die konfigurierten Aktionen aus.
|
||||
*
|
||||
* @author Andreas Penski
|
||||
*/
|
||||
@Slf4j
|
||||
public class CommandLineApplication {
|
||||
|
||||
private static final Option HELP = Option.builder("?").longOpt("help").argName("Help").desc("Displays this help").build();
|
||||
|
||||
private static final Option SCENARIOS = Option.builder("s").required().longOpt("scenarios").hasArg()
|
||||
.desc("Location of scenarios.xml e.g.").build();
|
||||
|
||||
private static final Option REPOSITORY = Option.builder("r").longOpt("repository").hasArg()
|
||||
.desc("Directory containing scenario content").build();
|
||||
|
||||
private static final Option PRINT = Option.builder("p").longOpt("print").desc("Prints the check result to stdout").build();
|
||||
|
||||
private static final Option OUTPUT = Option.builder("o").longOpt("output-directory")
|
||||
.desc("Defines the out directory for results. Defaults to cwd").hasArg().build();
|
||||
|
||||
private static final Option EXTRACT_HTML = Option.builder("h").longOpt("html")
|
||||
.desc("Extract and save any html content within result as a separate file ").build();
|
||||
|
||||
private static final Option DEBUG = Option.builder("d").longOpt("debug").desc("Prints some more debug information").build();
|
||||
|
||||
private static final Option CHECK_ASSERTIONS = Option.builder("c").longOpt("check-assertions").hasArg()
|
||||
.desc("Check the result using defined assertions").argName("assertions-file").build();
|
||||
|
||||
private CommandLineApplication() {
|
||||
// main class -> hide constructor
|
||||
}
|
||||
|
||||
/**
|
||||
* Main-Funktion für die Kommandozeilen-Applikation.
|
||||
*
|
||||
* @param args die Eingabe-Argumente
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
final int resultStatus = mainProgram(args);
|
||||
System.exit(resultStatus);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hauptprogramm für die Kommandozeilen-Applikation.
|
||||
*
|
||||
* @param args die Eingabe-Argumente
|
||||
*/
|
||||
static int mainProgram(String[] args) {
|
||||
Options options = createOptions();
|
||||
if (isHelpRequested(args)) {
|
||||
printHelp(options);
|
||||
} else {
|
||||
try {
|
||||
CommandLineParser parser = new DefaultParser();
|
||||
final CommandLine cmd = parser.parse(options, args);
|
||||
if (cmd.getArgList().isEmpty()) {
|
||||
printHelp(createOptions());
|
||||
} else {
|
||||
return processActions(cmd);
|
||||
}
|
||||
} catch (ParseException e) {
|
||||
log.error("Error processing command line arguments: " + e.getMessage());
|
||||
printHelp(options);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static boolean isHelpRequested(String[] args) {
|
||||
Options helpOptions = createHelpOptions();
|
||||
try {
|
||||
CommandLineParser parser = new DefaultParser();
|
||||
CommandLine cmd = parser.parse(helpOptions, args, true);
|
||||
if (cmd.hasOption(HELP.getOpt()) || args.length == 0) {
|
||||
return true;
|
||||
}
|
||||
} catch (ParseException e) {
|
||||
// we can ignore that, we just look for the help parameters
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static int processActions(CommandLine cmd) {
|
||||
try {
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
CheckConfiguration d = new CheckConfiguration(determineDefinition(cmd));
|
||||
d.setScenarioRepository(determineRepository(cmd));
|
||||
InternalCheck check = new InternalCheck(d);
|
||||
Path outputDirectory = determineOutputDirectory(cmd);
|
||||
|
||||
if (cmd.hasOption(EXTRACT_HTML.getOpt())) {
|
||||
check.getCheckSteps().add(new ExtractHtmlContentAction(check.getContentRepository(), outputDirectory));
|
||||
}
|
||||
check.getCheckSteps().add(new SerializeReportAction(outputDirectory));
|
||||
if (cmd.hasOption(PRINT.getOpt())) {
|
||||
check.getCheckSteps().add(new PrintReportAction());
|
||||
}
|
||||
if (cmd.hasOption(CHECK_ASSERTIONS.getOpt())) {
|
||||
Assertions assertions = loadAssertions(cmd.getOptionValue(CHECK_ASSERTIONS.getOpt()));
|
||||
check.getCheckSteps().add(new CheckAssertionAction(assertions, ObjectFactory.createProcessor()));
|
||||
}
|
||||
|
||||
log.info("Setup completed in {}ms\n", System.currentTimeMillis() - start);
|
||||
|
||||
final Collection<Path> targets = determineTestTargets(cmd);
|
||||
start = System.currentTimeMillis();
|
||||
final List<Input> input = targets.stream().map(InputFactory::read).collect(Collectors.toList());
|
||||
boolean result = check.checkInput(input);
|
||||
log.info("Processing {} object(s) completed in {}ms", input.size(), System.currentTimeMillis() - start);
|
||||
return result ? 0 : 1;
|
||||
|
||||
} catch (Exception e) {
|
||||
if (cmd.hasOption(DEBUG.getOpt())) {
|
||||
log.error(e.getMessage(), e);
|
||||
} else {
|
||||
log.error(e.getMessage());
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
private static Assertions loadAssertions(String optionValue) {
|
||||
Path p = Paths.get(optionValue);
|
||||
Assertions a = null;
|
||||
if (Files.exists(p)) {
|
||||
ConversionService c = new ConversionService();
|
||||
c.initialize(de.kosit.validationtool.cmd.assertions.ObjectFactory.class.getPackage());
|
||||
a = c.readXml(p.toUri(), Assertions.class);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
private static Path determineOutputDirectory(CommandLine cmd) {
|
||||
final String value = cmd.getOptionValue(OUTPUT.getOpt());
|
||||
Path fir;
|
||||
if (StringUtils.isNotBlank(value)) {
|
||||
fir = Paths.get(value);
|
||||
if ((!Files.exists(fir) && !fir.toFile().mkdirs()) || !Files.isDirectory(fir)) {
|
||||
throw new IllegalStateException(String.format("Invalid target directory %s specified", value));
|
||||
}
|
||||
} else {
|
||||
fir = Paths.get(""/* cwd */);
|
||||
}
|
||||
return fir;
|
||||
}
|
||||
|
||||
private static Collection<Path> determineTestTargets(CommandLine cmd) {
|
||||
Collection<Path> targets = new ArrayList<>();
|
||||
if (!cmd.getArgList().isEmpty()) {
|
||||
cmd.getArgList().forEach(e -> targets.addAll(determineTestTarget(e)));
|
||||
}
|
||||
if (targets.isEmpty()) {
|
||||
throw new IllegalStateException("No test targets found. Nothing to check. Will quit now!");
|
||||
}
|
||||
return targets;
|
||||
}
|
||||
|
||||
private static Collection<Path> determineTestTarget(String s) {
|
||||
Path d = Paths.get(s);
|
||||
if (Files.isDirectory(d)) {
|
||||
return listDirectoryTargets(d);
|
||||
} else if (Files.exists(d)) {
|
||||
return Collections.singleton(d);
|
||||
}
|
||||
log.warn("The specified test target {} does not exist. Will be ignored", s);
|
||||
return Collections.emptyList();
|
||||
|
||||
}
|
||||
|
||||
private static Collection<Path> listDirectoryTargets(Path d) {
|
||||
try {
|
||||
return Files.list(d).filter(path -> path.toString().endsWith(".xml")).collect(Collectors.toList());
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException("IOException while liste directory content. Can not determine test targets.", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static URI determineRepository(CommandLine cmd) throws MalformedURLException {
|
||||
if (checkOptionWithValue(REPOSITORY, cmd)) {
|
||||
Path d = Paths.get(cmd.getOptionValue(REPOSITORY.getOpt()));
|
||||
if (Files.isDirectory(d)) {
|
||||
return d.toUri();
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
String.format("Not a valid path for scenario definition specified: '%s'", d.toAbsolutePath()));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static URI determineDefinition(CommandLine cmd) throws MalformedURLException {
|
||||
checkOptionWithValue(SCENARIOS, cmd);
|
||||
Path f = Paths.get(cmd.getOptionValue(SCENARIOS.getOpt()));
|
||||
if (Files.isRegularFile(f)) {
|
||||
return f.toAbsolutePath().toUri();
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
String.format("Not a valid path for scenario definition specified: '%s'", f.toAbsolutePath()));
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean checkOptionWithValue(Option option, CommandLine cmd) {
|
||||
String opt = option.getOpt();
|
||||
if (cmd.hasOption(opt)) {
|
||||
String value = cmd.getOptionValue(opt);
|
||||
if (StringUtils.isNoneBlank(value)) {
|
||||
return true;
|
||||
} else {
|
||||
throw new IllegalArgumentException(String.format("Option value required for Option '%s'", option.getLongOpt()));
|
||||
}
|
||||
} else if (option.isRequired()) {
|
||||
|
||||
throw new IllegalArgumentException(String.format("Option '%s' required ", option.getLongOpt()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void printHelp(Options options) {
|
||||
// automatically generate the help statement
|
||||
HelpFormatter formatter = new HelpFormatter();
|
||||
formatter.printHelp("check-tool -s <scenario-config-file> [OPTIONS] [FILE]... ", options, false);
|
||||
}
|
||||
|
||||
private static Options createHelpOptions() {
|
||||
Options options = new Options();
|
||||
options.addOption(HELP);
|
||||
return options;
|
||||
}
|
||||
|
||||
private static Options createOptions() {
|
||||
Options options = new Options();
|
||||
options.addOption(HELP);
|
||||
options.addOption(SCENARIOS);
|
||||
options.addOption(REPOSITORY);
|
||||
options.addOption(PRINT);
|
||||
options.addOption(OUTPUT);
|
||||
options.addOption(EXTRACT_HTML);
|
||||
options.addOption(DEBUG);
|
||||
options.addOption(CHECK_ASSERTIONS);
|
||||
return options;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* 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.cmd;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.xml.transform.dom.DOMSource;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import de.kosit.validationtool.impl.ContentRepository;
|
||||
import de.kosit.validationtool.impl.tasks.CheckAction;
|
||||
|
||||
import net.sf.saxon.s9api.*;
|
||||
|
||||
/**
|
||||
* Extrahiert HTML-Dokumente aus dem Report und persistiert diese im konfigurierten Ausgabe-Verzeichnis.
|
||||
*
|
||||
* @author Andreas Penski
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class ExtractHtmlContentAction implements CheckAction {
|
||||
|
||||
private static final QName NAME_ATTRIBUTE = new QName("data-report-type");
|
||||
|
||||
private final ContentRepository repository;
|
||||
|
||||
private final Path outputDirectory;
|
||||
|
||||
private XPathExecutable executable;
|
||||
|
||||
@Override
|
||||
public void check(Bag results) {
|
||||
try {
|
||||
final XPathSelector selector = getSelector();
|
||||
DocumentBuilder documentBuilder = repository.getProcessor().newDocumentBuilder();
|
||||
|
||||
final XdmNode xdmSource = documentBuilder.build(new DOMSource(results.getReport()));
|
||||
selector.setContextItem(xdmSource);
|
||||
selector.forEach(m -> print(results.getName(), m));
|
||||
|
||||
} catch (SaxonApiException e) {
|
||||
throw new IllegalStateException("Can not extract html content", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void print(String origName, XdmItem xdmItem) {
|
||||
XdmNode node = (XdmNode) xdmItem;
|
||||
final String name = origName + "-" + node.getAttributeValue(NAME_ATTRIBUTE);
|
||||
final Path file = outputDirectory.resolve(name + ".html");
|
||||
final Serializer serializer = repository.getProcessor().newSerializer(file.toFile());
|
||||
try {
|
||||
log.info("Writing report html '{}' to {}", name, file.toAbsolutePath());
|
||||
serializer.serializeNode(node);
|
||||
} catch (SaxonApiException e) {
|
||||
log.info("Error extracting html content to {}", file.toAbsolutePath(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private XPathSelector getSelector() {
|
||||
if (executable == null) {
|
||||
Map<String, String> ns = new HashMap<>();
|
||||
ns.put("html", "http://www.w3.org/1999/xhtml");
|
||||
executable = repository.createXPath("//html:html", ns);
|
||||
}
|
||||
return executable.load();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSkipped(Bag results) {
|
||||
if (results.getReport() == null) {
|
||||
log.warn("Can not extract html content. No report document found");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
83
src/main/java/de/kosit/validationtool/cmd/InternalCheck.java
Normal file
83
src/main/java/de/kosit/validationtool/cmd/InternalCheck.java
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* 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.cmd;
|
||||
|
||||
import de.kosit.validationtool.api.CheckConfiguration;
|
||||
import de.kosit.validationtool.api.Input;
|
||||
import de.kosit.validationtool.impl.DefaultCheck;
|
||||
import de.kosit.validationtool.impl.model.Result;
|
||||
import de.kosit.validationtool.impl.tasks.CheckAction;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Simple Erweiterung der Klasse {@link DefaultCheck} um das Ergebnis der Assertion-Prüfung auszwerten und auszugeben.
|
||||
* Diese Klasse stellt keine fachlicher Erweiterung des eigentlichen Prüfvorganges dar!
|
||||
*
|
||||
* @author Andreas Penski
|
||||
*/
|
||||
@Slf4j
|
||||
class InternalCheck extends DefaultCheck {
|
||||
|
||||
/**
|
||||
* Erzeugt eine neue Instanz mit der angegebenen Konfiguration.
|
||||
*
|
||||
* @param configuration die Konfiguration
|
||||
*/
|
||||
public InternalCheck(CheckConfiguration configuration) {
|
||||
super(configuration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prüft die Prüflinge und gibt Informationen über etwaige Assertions aus.
|
||||
*
|
||||
* @param input die Prüflinge
|
||||
* @return false wenn es Assertion-Fehler gibt, sonst true
|
||||
*/
|
||||
public boolean checkInput(List<Input> input) {
|
||||
List<CheckAction.Bag> results = new ArrayList<>();
|
||||
input.forEach(i -> {
|
||||
CheckAction.Bag bag = new CheckAction.Bag(i, createReport());
|
||||
runCheckInternal(bag);
|
||||
results.add(bag);
|
||||
});
|
||||
|
||||
return printAndEvaluate(results);
|
||||
|
||||
}
|
||||
|
||||
private boolean printAndEvaluate(List<CheckAction.Bag> results) {
|
||||
final List<Result<Integer, String>> asserts = results.stream().filter(r -> r.getAssertionResult() != null)
|
||||
.map(CheckAction.Bag::getAssertionResult).collect(Collectors.toList());
|
||||
int checkAssertions = asserts.stream().mapToInt(e -> e.getObject()).sum();
|
||||
int failedAssertions = asserts.stream().mapToInt(e -> e.getErrors().size()).sum();
|
||||
|
||||
if (failedAssertions > 0) {
|
||||
log.error("Assertion check failed.\n\nAssertions run: {}, Assertions failed: {}\n", checkAssertions, failedAssertions);
|
||||
} else if (checkAssertions > 0) {
|
||||
log.info("Assertion check successful.\n\nAssertions run: {}, Assertions failed: {}\n", checkAssertions, failedAssertions);
|
||||
}
|
||||
return failedAssertions == 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* 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.cmd;
|
||||
|
||||
import java.io.StringWriter;
|
||||
|
||||
import javax.xml.transform.Result;
|
||||
import javax.xml.transform.Source;
|
||||
import javax.xml.transform.Transformer;
|
||||
import javax.xml.transform.TransformerException;
|
||||
import javax.xml.transform.dom.DOMSource;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import de.kosit.validationtool.impl.ObjectFactory;
|
||||
import de.kosit.validationtool.impl.tasks.CheckAction;
|
||||
|
||||
/**
|
||||
* Gibt das Ergebnis-Document auf std-out aus.
|
||||
*
|
||||
* @author Andreas Penski
|
||||
*/
|
||||
@Slf4j
|
||||
public class PrintReportAction implements CheckAction {
|
||||
|
||||
@Override
|
||||
public void check(Bag results) {
|
||||
try {
|
||||
Transformer transformer = ObjectFactory.createTransformer(true);
|
||||
final StringWriter writer = new StringWriter();
|
||||
Result output = new StreamResult(writer);
|
||||
Source input = new DOMSource(results.getReport());
|
||||
transformer.transform(input, output);
|
||||
System.out.print(writer.toString());
|
||||
} catch (TransformerException e) {
|
||||
log.error("Error while printing result to stdout", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* 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.cmd;
|
||||
|
||||
import de.kosit.validationtool.impl.ObjectFactory;
|
||||
import de.kosit.validationtool.impl.tasks.CheckAction;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import javax.xml.transform.Result;
|
||||
import javax.xml.transform.Source;
|
||||
import javax.xml.transform.Transformer;
|
||||
import javax.xml.transform.TransformerException;
|
||||
import javax.xml.transform.dom.DOMSource;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
import java.nio.file.Path;
|
||||
|
||||
/**
|
||||
* Schreibt das Prüfergebnis als XML-Dokument an eine definierte Stelle.
|
||||
*
|
||||
* @author Andreas Penski
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class SerializeReportAction implements CheckAction {
|
||||
|
||||
private final Path outputDirectory;
|
||||
|
||||
@Override
|
||||
public void check(Bag results) {
|
||||
final Path file = outputDirectory.resolve(results.getName() + "-report.xml");
|
||||
try {
|
||||
log.info("Serializing result to {}", file.toAbsolutePath());
|
||||
Transformer transformer = ObjectFactory.createTransformer(true);
|
||||
Result output = new StreamResult(file.toFile());
|
||||
Source input = new DOMSource(results.getReport());
|
||||
transformer.transform(input, output);
|
||||
} catch (TransformerException e) {
|
||||
log.error("Can not serialize result report to {}", file.toAbsolutePath(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSkipped(Bag results) {
|
||||
if (results.getReport() == null) {
|
||||
log.warn("Can not serialize result report. No document found");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,168 @@
|
|||
/*
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,175 @@
|
|||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,241 @@
|
|||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
137
src/main/java/de/kosit/validationtool/impl/DefaultCheck.java
Normal file
137
src/main/java/de/kosit/validationtool/impl/DefaultCheck.java
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
}
|
||||
256
src/main/java/de/kosit/validationtool/impl/ObjectFactory.java
Normal file
256
src/main/java/de/kosit/validationtool/impl/ObjectFactory.java
Normal file
|
|
@ -0,0 +1,256 @@
|
|||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,173 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,187 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* 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();
|
||||
}
|
||||
80
src/main/java/de/kosit/validationtool/impl/model/Result.java
Normal file
80
src/main/java/de/kosit/validationtool/impl/model/Result.java
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* 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());
|
||||
}
|
||||
}
|
||||
55
src/main/model/binding/global.xjb
Normal file
55
src/main/model/binding/global.xjb
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<!--
|
||||
~ 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.
|
||||
-->
|
||||
|
||||
<jaxb:bindings
|
||||
xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
|
||||
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
|
||||
xmlns:inheritance="http://jaxb2-commons.dev.java.net/basic/inheritance"
|
||||
jaxb:extensionBindingPrefixes="inheritance"
|
||||
version="2.1">
|
||||
<jaxb:globalBindings>
|
||||
<xjc:serializable uid="-1"/>
|
||||
</jaxb:globalBindings>
|
||||
|
||||
|
||||
<jaxb:bindings schemaLocation="../xsd/createReportInput.xsd">
|
||||
<jaxb:schemaBindings>
|
||||
<jaxb:package name="de.kosit.validationtool.model.reportInput"/>
|
||||
</jaxb:schemaBindings>
|
||||
<jaxb:bindings node="//xs:complexType[@name='XMLSyntaxError']">
|
||||
<inheritance:extends>de.kosit.validationtool.impl.model.BaseXMLSyntaxError</inheritance:extends>
|
||||
</jaxb:bindings>
|
||||
</jaxb:bindings>
|
||||
<jaxb:bindings schemaLocation="../xsd/scenarios.xsd">
|
||||
<jaxb:schemaBindings>
|
||||
<jaxb:package name="de.kosit.validationtool.model.scenarios"/>
|
||||
</jaxb:schemaBindings>
|
||||
<jaxb:bindings node="//xs:complexType[@name='ScenarioType']">
|
||||
<inheritance:extends>de.kosit.validationtool.impl.model.BaseScenario</inheritance:extends>
|
||||
</jaxb:bindings>
|
||||
</jaxb:bindings>
|
||||
<jaxb:bindings schemaLocation="../xsd/assertions.xsd">
|
||||
<jaxb:schemaBindings>
|
||||
<jaxb:package name="de.kosit.validationtool.cmd.assertions"/>
|
||||
</jaxb:schemaBindings>
|
||||
</jaxb:bindings>
|
||||
|
||||
</jaxb:bindings>
|
||||
71
src/main/model/xsd/assertions.xsd
Normal file
71
src/main/model/xsd/assertions.xsd
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ 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.
|
||||
-->
|
||||
|
||||
<!-- $Id: assertions.xsd 7554 2017-09-13 14:27:21Z fbuettner $ -->
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:a="http://www.xoev.de/de/validator/framework/1/assertions"
|
||||
targetNamespace="http://www.xoev.de/de/validator/framework/1/assertions" version="1.0.0"
|
||||
elementFormDefault="qualified"
|
||||
attributeFormDefault="unqualified">
|
||||
|
||||
<xs:element name="assertions">
|
||||
<xs:annotation>
|
||||
<xs:documentation>In diesem Dokument werden zum Test einer Prüftoolkonfiguration Zusicherungen zu einzelnen
|
||||
Prüfberichten beschrieben. Ein
|
||||
solches Dokument kann der Kommandozeilenversion des Prüftools über --check-assertions übergeben werden.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="namespace" type="a:NamespaceType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="assertion" type="a:AssertionType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
<xs:complexType name="NamespaceType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Definition eines Präfix für einen Namensraum, zur Verwendung in nachfolgenden
|
||||
assertion-Elementen.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:anyURI">
|
||||
<xs:attribute name="prefix" use="required"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="AssertionType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Zusicherung: für das in report-doc angegebene Dokument (relativ zum aktuellen
|
||||
Ausgabeverzeichnis) hat der angebene
|
||||
XPath-Test den "Effective Truth Value" true(). Im Textknoten kann eine textuelle Zusammenfassung des
|
||||
Tests stehen.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:token">
|
||||
<xs:attribute name="report-doc" type="xs:anyURI" use="required"/>
|
||||
<xs:attribute name="test" type="xs:string" use="required"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
|
||||
</xs:schema>
|
||||
153
src/main/model/xsd/createReportInput.xsd
Normal file
153
src/main/model/xsd/createReportInput.xsd
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ 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.
|
||||
-->
|
||||
|
||||
<!-- $Id$ -->
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:in="http://www.xoev.de/de/validator/framework/1/createreportinput"
|
||||
xmlns:s="http://www.xoev.de/de/validator/framework/1/scenarios" targetNamespace="http://www.xoev.de/de/validator/framework/1/createreportinput" version="1.0.0"
|
||||
elementFormDefault="qualified" attributeFormDefault="unqualified">
|
||||
|
||||
<xs:import namespace="http://www.xoev.de/de/validator/framework/1/scenarios" schemaLocation="scenarios.xsd"/>
|
||||
|
||||
<xs:element name="createReportInput">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="engine" type="in:EngineType"/>
|
||||
<xs:element name="timestamp" type="xs:dateTime"/>
|
||||
<xs:element name="documentIdentification" type="in:DocumentIdentificationType"/>
|
||||
<xs:element ref="s:scenario" minOccurs="0"/>
|
||||
<xs:element name="validationResultsWellformedness" type="in:ValidationResultsWellformedness" minOccurs="0"/>
|
||||
<xs:element name="validationResultsXmlSchema" type="in:ValidationResultsXmlSchema" minOccurs="0"/>
|
||||
<xs:element name="validationResultsSchematron" type="in:ValidationResultsSchematron" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="processingError" type="in:ProcessingError" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="frameworkVersion" type="xs:string" use="required"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
<xs:complexType name="Document">
|
||||
<xs:sequence>
|
||||
<xs:any processContents="skip" namespace="##any"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="ValidationResultsWellformedness">
|
||||
<xs:sequence>
|
||||
<xs:element name="xmlSyntaxError" type="in:XMLSyntaxError" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="ValidationResultsXmlSchema">
|
||||
<xs:sequence>
|
||||
<xs:element ref="s:resource" maxOccurs="unbounded"/>
|
||||
<xs:element name="xmlSyntaxError" type="in:XMLSyntaxError" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:annotation>
|
||||
<xs:documentation>In alignment with
|
||||
http://docs.oracle.com/javase/8/docs/api/org/xml/sax/ErrorHandler.html and
|
||||
http://docs.oracle.com/javase/8/docs/api/org/xml/sax/SAXParseException.html</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexType name="XMLSyntaxError">
|
||||
<xs:sequence>
|
||||
<xs:element name="message" type="xs:normalizedString"/>
|
||||
<xs:element name="severity" type="in:XMLSyntaxErrorSeverity"/>
|
||||
<xs:element name="rowNumber" type="xs:int" minOccurs="0"/>
|
||||
<xs:element name="columnNumber" type="xs:int" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:simpleType name="XMLSyntaxErrorSeverity">
|
||||
<xs:restriction base="xs:token">
|
||||
<xs:enumeration value="SEVERITY_WARNING"/>
|
||||
<xs:enumeration value="SEVERITY_ERROR"/>
|
||||
<xs:enumeration value="SEVERITY_FATAL_ERROR"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:complexType name="ValidationResultsSchematron">
|
||||
<xs:sequence>
|
||||
<xs:element ref="s:resource"/>
|
||||
<xs:element name="results">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:any namespace="##any" processContents="skip"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="DocumentIdentificationType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Dient der eindeutigen Identifikation des geprüften Dokuments anhand seines Hashwertes, der durch eine Dokumentenreferenz
|
||||
ergänzt werden kann.</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:sequence>
|
||||
<xs:element name="documentHash">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Angaben zum Hashwert des geprüften Dokuments.</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="hashAlgorithm" type="xs:normalizedString">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Benennung eines Algorithmus zur Berechnung des Hashwerts.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element name="hashValue" type="xs:base64Binary">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Der Hashwert des geprüften Dokuments bei Anwendung des bezeichneten Algorithmus.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="documentReference" type="xs:normalizedString">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Eine von der prüfenden Organisationseinheit festgelegte, möglichst eindeutige Referenz des geprüften
|
||||
Dokuments.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="EngineType">
|
||||
<xs:sequence>
|
||||
<xs:element name="name" type="xs:normalizedString"/>
|
||||
<xs:element name="info" minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:complexType>
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:normalizedString">
|
||||
<xs:attribute name="key" type="xs:NMTOKEN" use="required"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="ProcessingError">
|
||||
<xs:sequence>
|
||||
<xs:element name="error" type="xs:string" minOccurs="1" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
|
||||
</xs:schema>
|
||||
137
src/main/model/xsd/scenarios.xsd
Normal file
137
src/main/model/xsd/scenarios.xsd
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ 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.
|
||||
-->
|
||||
|
||||
<!-- $Id$ -->
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:s="http://www.xoev.de/de/validator/framework/1/scenarios"
|
||||
targetNamespace="http://www.xoev.de/de/validator/framework/1/scenarios" version="1.0.0" elementFormDefault="qualified" attributeFormDefault="unqualified">
|
||||
|
||||
<xs:element name="scenarios">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="name" type="xs:token"/>
|
||||
<xs:element minOccurs="0" name="author" type="xs:token"/>
|
||||
<xs:element name="date" type="xs:date"/>
|
||||
<xs:element name="description" type="s:DescriptionType"/>
|
||||
<xs:element ref="s:scenario" minOccurs="1" maxOccurs="unbounded"/>
|
||||
<xs:element name="noScenarioReport" type="s:NoScenarioReportType"/>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="frameworkVersion" type="xs:string" use="required"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
<xs:element name="scenario" type="s:ScenarioType"/>
|
||||
|
||||
<xs:complexType name="NoScenarioReportType">
|
||||
<xs:sequence>
|
||||
<xs:element ref="s:resource"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="DescriptionType">
|
||||
<xs:choice maxOccurs="unbounded">
|
||||
<xs:element name="p" type="xs:normalizedString"/>
|
||||
<xs:element name="ol">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element maxOccurs="unbounded" name="li" type="xs:normalizedString"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="ul">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element maxOccurs="unbounded" name="li" type="xs:normalizedString"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:choice>
|
||||
</xs:complexType>
|
||||
|
||||
<!-- TODO: Prüfen, ob restriction passt -->
|
||||
<xs:simpleType name="ErrorLevelType">
|
||||
<xs:restriction base="xs:token">
|
||||
<xs:enumeration value="error"/>
|
||||
<xs:enumeration value="warning"/>
|
||||
<xs:enumeration value="information"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:simpleType name="Tokens">
|
||||
<xs:list itemType="xs:token"/>
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:complexType name="ScenarioType">
|
||||
<xs:sequence>
|
||||
<xs:element name="name" type="xs:token"/>
|
||||
<xs:element minOccurs="0" name="description" type="s:DescriptionType"/>
|
||||
<xs:element minOccurs="0" maxOccurs="unbounded" name="namespace" type="s:NamespaceType"/>
|
||||
<xs:element name="match" type="xs:string"/>
|
||||
<xs:element name="validateWithXmlSchema" type="s:ValidateWithXmlSchema"/>
|
||||
<xs:element name="validateWithSchematron" maxOccurs="unbounded" minOccurs="0" type="s:ValidateWithSchematron"/>
|
||||
<xs:element name="createReport" type="s:CreateReportType"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:element name="resource" type="s:ResourceType"/>
|
||||
|
||||
<xs:complexType name="NamespaceType">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:anyURI">
|
||||
<xs:attribute name="prefix" use="required"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="ResourceType">
|
||||
<xs:sequence>
|
||||
<xs:element name="name" type="xs:token"/>
|
||||
<xs:element name="location" type="xs:anyURI"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="ValidateWithXmlSchema">
|
||||
<xs:sequence>
|
||||
<xs:element ref="s:resource" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="ValidateWithSchematron">
|
||||
<xs:sequence>
|
||||
<xs:element ref="s:resource"/>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="psvi" type="xs:boolean" default="false" use="optional"/>
|
||||
</xs:complexType>
|
||||
|
||||
|
||||
<xs:complexType name="CreateReportType">
|
||||
<xs:sequence>
|
||||
<xs:element ref="s:resource"/>
|
||||
<xs:element maxOccurs="3" minOccurs="0" name="customLevel" type="s:CustomErrorLevel"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="CustomErrorLevel">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="s:Tokens">
|
||||
<xs:attribute name="level" type="s:ErrorLevelType" use="required"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
</xs:schema>
|
||||
51
src/main/resources/simplelogger.properties
Normal file
51
src/main/resources/simplelogger.properties
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
# SLF4J's SimpleLogger configuration file for the command line client
|
||||
# Simple implementation of Logger that sends all enabled log messages, for all defined loggers, to System.err.
|
||||
|
||||
# Default logging detail level for all instances of SimpleLogger.
|
||||
# Must be one of ("trace", "debug", "info", "warn", or "error").
|
||||
# If not specified, defaults to "info".
|
||||
org.slf4j.simpleLogger.defaultLogLevel=info
|
||||
|
||||
|
||||
# Set to true if you want the current date and time to be included in output messages.
|
||||
# Default is false, and will output the number of milliseconds elapsed since startup.
|
||||
org.slf4j.simpleLogger.showDateTime=true
|
||||
|
||||
# The date and time format to be used in the output messages.
|
||||
# The pattern describing the date and time format is the same that is used in java.text.SimpleDateFormat.
|
||||
# If the format is not specified or is invalid, the default format is used.
|
||||
# The default format is yyyy-MM-dd HH:mm:ss:SSS Z.
|
||||
org.slf4j.simpleLogger.dateTimeFormat=yyyy-MM-dd HH:mm:ss
|
||||
|
||||
# Set to true if you want to output the current thread name.
|
||||
# Defaults to true.
|
||||
org.slf4j.simpleLogger.showThreadName=false
|
||||
|
||||
# Set to true if you want the Logger instance name to be included in output messages.
|
||||
# Defaults to true.
|
||||
org.slf4j.simpleLogger.showLogName=false
|
||||
|
||||
# Set to true if you want the last component of the name to be included in output messages.
|
||||
# Defaults to false.
|
||||
org.slf4j.simpleLogger.showShortLogName=false
|
||||
|
||||
org.slf4j.simpleLogger.levelInBrackets=true
|
||||
Loading…
Add table
Add a link
Reference in a new issue