Commit 1bc2d658 authored by Matthias Betz's avatar Matthias Betz
Browse files

implement schematron with different error types

parent b0f6085c
Pipeline #1604 failed with stage
in 1 minute and 31 seconds
......@@ -65,7 +65,12 @@ public abstract class Checkable implements Serializable {
* @param c the check from which the check method is called with the Checkable
* instance as parameter.
*/
public abstract void accept(Check c);
public void accept(Check c) {
if (c.canExecute(this)) {
c.check(this);
}
setValidated(true);
}
/**
* The GML-ID of the checkable. This is necessary so specific features can be
......
......@@ -101,4 +101,8 @@ public class ErrorId implements Serializable {
return name;
}
public String getIdString() {
return name;
}
}
......@@ -19,6 +19,8 @@
package de.hft.stuttgart.citydoctor2.check;
import de.hft.stuttgart.citydoctor2.check.error.AllPolygonsWrongOrientationError;
import de.hft.stuttgart.citydoctor2.check.error.AttributeMissingError;
import de.hft.stuttgart.citydoctor2.check.error.AttributeValueWrongError;
import de.hft.stuttgart.citydoctor2.check.error.ConsecutivePointSameError;
import de.hft.stuttgart.citydoctor2.check.error.DependenciesNotMetError;
import de.hft.stuttgart.citydoctor2.check.error.MultipleConnectedComponentsError;
......@@ -122,5 +124,9 @@ public interface ErrorVisitor {
public void visit(SurfaceUnfragmentedError err);
public void visit(TinyEdgeError err);
public void visit(AttributeMissingError err);
public void visit(AttributeValueWrongError err);
}
/*-
* Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart
*
* This file is part of CityDoctor2.
*
* CityDoctor2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* CityDoctor2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with CityDoctor2. If not, see <https://www.gnu.org/licenses/>.
*/
package de.hft.stuttgart.citydoctor2.check.error;
import de.hft.stuttgart.citydoctor2.check.CheckError;
import de.hft.stuttgart.citydoctor2.check.ErrorId;
import de.hft.stuttgart.citydoctor2.check.ErrorReport;
import de.hft.stuttgart.citydoctor2.check.ErrorType;
import de.hft.stuttgart.citydoctor2.check.ErrorVisitor;
import de.hft.stuttgart.citydoctor2.check.HealingMethod;
import de.hft.stuttgart.citydoctor2.check.ModificationListener;
import de.hft.stuttgart.citydoctor2.datastructure.CityObject;
import de.hft.stuttgart.citydoctor2.datastructure.GmlElement;
public class AttributeMissingError implements CheckError {
private static final long serialVersionUID = 185026674309965067L;
public static final ErrorId ID = new ErrorId("SEM_ATTRIBUTE_MISSING");
private CityObject co;
private boolean generic;
private String childId;
private String nameOfAttribute;
public AttributeMissingError(CityObject co, String childId, String nameOfAttribute, boolean generic) {
this.co = co;
this.childId = childId;
this.nameOfAttribute = nameOfAttribute;
this.generic = generic;
}
@Override
public ErrorType getType() {
return ErrorType.ERROR;
}
@Override
public ErrorId getErrorId() {
return ID;
}
public String getChildId() {
return childId;
}
public boolean isGeneric() {
return generic;
}
public String getNameOfAttribute() {
return nameOfAttribute;
}
@Override
public GmlElement getFeature() {
return co;
}
@Override
public void accept(ErrorVisitor errorVisitor) {
errorVisitor.visit(this);
}
@Override
public boolean accept(HealingMethod method, ModificationListener l) {
return method.visit(this, l);
}
@Override
public void report(ErrorReport report) {
report.add("childId", childId);
report.add("name", nameOfAttribute);
report.add("generic", "" + generic);
}
}
/*-
* Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart
*
* This file is part of CityDoctor2.
*
* CityDoctor2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* CityDoctor2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with CityDoctor2. If not, see <https://www.gnu.org/licenses/>.
*/
package de.hft.stuttgart.citydoctor2.check.error;
import de.hft.stuttgart.citydoctor2.check.CheckError;
import de.hft.stuttgart.citydoctor2.check.ErrorId;
import de.hft.stuttgart.citydoctor2.check.ErrorReport;
import de.hft.stuttgart.citydoctor2.check.ErrorType;
import de.hft.stuttgart.citydoctor2.check.ErrorVisitor;
import de.hft.stuttgart.citydoctor2.check.HealingMethod;
import de.hft.stuttgart.citydoctor2.check.ModificationListener;
import de.hft.stuttgart.citydoctor2.datastructure.CityObject;
import de.hft.stuttgart.citydoctor2.datastructure.GmlElement;
public class AttributeValueWrongError implements CheckError {
private static final long serialVersionUID = 6106964709204961560L;
public static final ErrorId ID = new ErrorId("SEM_ATTRIBUTE_WRONG_VALUE");
private CityObject co;
private boolean generic;
private String childId;
private String nameOfAttribute;
public AttributeValueWrongError(CityObject co, String childId, String nameOfAttribute, boolean generic) {
this.co = co;
this.childId = childId;
this.nameOfAttribute = nameOfAttribute;
this.generic = generic;
}
@Override
public ErrorType getType() {
return ErrorType.ERROR;
}
@Override
public ErrorId getErrorId() {
return ID;
}
@Override
public GmlElement getFeature() {
return co;
}
public String getChildId() {
return childId;
}
public boolean isGeneric() {
return generic;
}
public String getNameOfAttribute() {
return nameOfAttribute;
}
@Override
public void accept(ErrorVisitor errorVisitor) {
errorVisitor.visit(this);
}
@Override
public boolean accept(HealingMethod method, ModificationListener l) {
return method.visit(this, l);
}
@Override
public void report(ErrorReport report) {
report.add("childId", childId);
report.add("name", nameOfAttribute);
report.add("generic", "" + generic);
}
}
......@@ -31,10 +31,19 @@ public class SchematronError implements CheckError {
private static final long serialVersionUID = -2964084500589868928L;
private String text;
private String errorId;
private String gmlId;
private String childId;
private String nameOfAttribute;
private boolean generic;
public SchematronError(String text) {
this.text = text;
public SchematronError(String errorId, String gmlId, String childId, String nameOfAttribute, boolean generic) {
this.errorId = errorId;
this.gmlId = gmlId;
this.childId = childId;
this.nameOfAttribute = nameOfAttribute;
this.generic = generic;
}
@Override
......@@ -49,18 +58,34 @@ public class SchematronError implements CheckError {
@Override
public void report(ErrorReport report) {
report.add("Description", text);
report.add("errorId", errorId);
}
@Override
public String toString() {
return "SchematronError [text=" + text + "]";
return "SchematronError [text=" + errorId + "]";
}
public String getText() {
return text;
public String getChildId() {
return childId;
}
public String getGmlId() {
return gmlId;
}
public String getNameOfAttribute() {
return nameOfAttribute;
}
public String getErrorIdString() {
return errorId;
}
public boolean isGeneric() {
return generic;
}
@Override
public ErrorType getType() {
return ErrorType.ERROR;
......
......@@ -413,11 +413,13 @@ public class Geometry extends GmlElement {
@Override
public void clearMetaInformation() {
for (Vertex v : vertices) {
v.clearAdjacentRings();
if (vertices != null) {
for (Vertex v : vertices) {
v.clearAdjacentRings();
}
vertices = null;
}
edges = null;
vertices = null;
edgeMap = null;
}
}
......@@ -25,7 +25,6 @@ import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.UncheckedIOException;
import de.hft.stuttgart.citydoctor2.check.Check;
import de.hft.stuttgart.citydoctor2.check.Checkable;
/**
......@@ -54,14 +53,6 @@ public abstract class GmlElement extends Checkable {
}
}
@Override
public void accept(Check c) {
if (c.canExecute(this)) {
c.check(this);
}
setValidated(true);
}
public void setGmlId(GmlId id) {
gmlId = id;
}
......
......@@ -47,13 +47,13 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.w3c.dom.Document;
import de.hft.stuttgart.citydoctor2.check.error.AttributeMissingError;
import de.hft.stuttgart.citydoctor2.check.error.AttributeValueWrongError;
import de.hft.stuttgart.citydoctor2.check.error.SchematronError;
import de.hft.stuttgart.citydoctor2.checkresult.utility.CheckReportWriteException;
import de.hft.stuttgart.citydoctor2.checks.Checks;
import de.hft.stuttgart.citydoctor2.checks.SvrlContentHandler;
import de.hft.stuttgart.citydoctor2.checks.util.FeatureCheckedListener;
import de.hft.stuttgart.citydoctor2.datastructure.Building;
import de.hft.stuttgart.citydoctor2.datastructure.BuildingPart;
import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel;
import de.hft.stuttgart.citydoctor2.datastructure.CityObject;
import de.hft.stuttgart.citydoctor2.datastructure.FeatureType;
......@@ -111,7 +111,7 @@ public class Checker {
public Checks getChecks() {
return checkConfig;
}
public CityDoctorModel getModel() {
return model;
}
......@@ -187,36 +187,47 @@ public class Checker {
SvrlContentHandler handler = executeSchematronValidationIfAvailable(config, model.getFile());
if (handler != null) {
model.addGlobalErrors(handler.getGeneralErrors());
Map<String, Checkable> featureMap = new HashMap<>();
Map<String, CityObject> featureMap = new HashMap<>();
model.createFeatureStream().forEach(f -> featureMap.put(f.getGmlId().getGmlString(), f));
for (Building b : model.getBuildings()) {
for (BuildingPart bp : b.getBuildingParts()) {
featureMap.put(bp.getGmlId().getGmlString(), bp);
}
}
handler.getFeatureErrors().forEach((k, v) -> {
if (k.trim().isEmpty()) {
// missing gml id, ignore?
return;
}
Checkable checkable = featureMap.get(k);
if (checkable == null) {
CityObject co = featureMap.get(k);
if (co == null) {
// gml id reported by schematron was not found, add to general errors
model.addGlobalError(v);
for (SchematronError se : v) {
model.addGlobalError(se);
}
} else {
checkable.addCheckResult(new CheckResult(CheckId.C_SEM_SCHEMATRON, ResultStatus.ERROR, v));
int count = 0;
for (SchematronError se : v) {
CheckError err;
if (AttributeMissingError.ID.getIdString().equals(se.getErrorIdString())) {
err = new AttributeMissingError(co, se.getChildId(), se.getNameOfAttribute(),
se.isGeneric());
} else if (AttributeValueWrongError.ID.getIdString().equals(se.getErrorIdString())) {
err = new AttributeValueWrongError(co, se.getChildId(), se.getNameOfAttribute(),
se.isGeneric());
} else {
throw new IllegalStateException(
"Unknown error ID was given in schematron file: " + se.getErrorIdString());
}
co.addCheckResult(new CheckResult(new CheckId("" + count), ResultStatus.ERROR, err));
count++;
}
}
});
}
isValidated = true;
}
public ValidationConfiguration getConfig() {
return config;
}
public static SvrlContentHandler executeSchematronValidationIfAvailable(ValidationConfiguration config,
File file) {
public static SvrlContentHandler executeSchematronValidationIfAvailable(ValidationConfiguration config, File file) {
if (config.getSchematronFilePath() != null && !config.getSchematronFilePath().isEmpty()) {
if (logger.isInfoEnabled()) {
logger.info(Localization.getText("Checker.schematronValidation"));
......@@ -372,7 +383,7 @@ public class Checker {
}
// check every feature
executeChecksForCityObject(co);
if (config.getParserConfiguration().useLowMemoryConsumption()) {
// low memory consumption, remove edges again
co.clearMetaInformation();
......@@ -448,10 +459,10 @@ public class Checker {
public static List<List<Check>> buildExecutionLayers(List<Check> checks) {
List<List<Check>> result = new ArrayList<>();
Set<Check> availableChecks = new HashSet<>(checks);
Set<CheckId> usedChecks = new HashSet<>();
while (!availableChecks.isEmpty()) {
List<Check> layer = new ArrayList<>();
Iterator<Check> iterator = availableChecks.iterator();
......@@ -464,7 +475,8 @@ public class Checker {
}
}
if (layer.isEmpty()) {
throw new IllegalStateException("There are checks that have dependencies that are not executed or are unknown");
throw new IllegalStateException(
"There are checks that have dependencies that are not executed or are unknown");
}
result.add(layer);
for (Check c : layer) {
......@@ -526,8 +538,10 @@ public class Checker {
for (SchematronError err : handler.getGeneralErrors()) {
reporter.reportGlobalError(err);
}
for (Entry<String, SchematronError> e : handler.getFeatureErrors().entrySet()) {
reporter.addError(e.getKey(), e.getValue());
for (Entry<String, List<SchematronError>> e : handler.getFeatureErrors().entrySet()) {
for (SchematronError se : e.getValue()) {
reporter.addError(e.getKey(), se);
}
}
}
reporter.finishReport();
......
......@@ -45,7 +45,7 @@ public class SvrlContentHandler implements ContentHandler {
private StringBuilder buffer;
private Map<String, SchematronError> featureErrors;
private Map<String, List<SchematronError>> featureErrors;
private List<SchematronError> generalErrors;
public SvrlContentHandler() {
......@@ -53,7 +53,7 @@ public class SvrlContentHandler implements ContentHandler {
generalErrors = new ArrayList<>();
}
public Map<String, SchematronError> getFeatureErrors() {
public Map<String, List<SchematronError>> getFeatureErrors() {
return featureErrors;
}
......@@ -104,13 +104,23 @@ public class SvrlContentHandler implements ContentHandler {
// not needed
if (nextIsTextContent && "text".equals(localName)) {
String text = buffer.toString();
int index = text.indexOf(": ");
if (index == -1) {
String[] split = text.split("\\|\\|");
if (split.length != 5) {
throw new IllegalStateException(
"Schematron File is not formed according to specification for CityDoctor.");
}
String gmlId = split[0];
String childId = split[1];
String errorId = split[2];
String nameOfAttribute = split[3];
boolean generic = Boolean.parseBoolean(split[4]);
SchematronError err = new SchematronError(errorId, gmlId, childId, nameOfAttribute, generic);
if (gmlId == null || gmlId.isEmpty()) {
// general error
generalErrors.add(new SchematronError(text));
generalErrors.add(err);
} else {
String gmlId = text.substring(0, index);
featureErrors.put(gmlId, new SchematronError(text));
List<SchematronError> errors = featureErrors.computeIfAbsent(gmlId, k -> new ArrayList<>());
errors.add(err);
}
buffer = null;
nextIsTextContent = false;
......
......@@ -39,7 +39,6 @@ import de.hft.stuttgart.citydoctor2.check.CheckResult;
import de.hft.stuttgart.citydoctor2.check.ErrorId;
import de.hft.stuttgart.citydoctor2.check.ResultStatus;
import de.hft.stuttgart.citydoctor2.check.ValidationConfiguration;
import de.hft.stuttgart.citydoctor2.check.error.SchematronError;
import de.hft.stuttgart.citydoctor2.checkresult.utility.CheckReportWriteException;
import de.hft.stuttgart.citydoctor2.datastructure.BoundarySurface;
import de.hft.stuttgart.citydoctor2.datastructure.BridgeObject;
......@@ -445,10 +444,8 @@ public class PdfStreamReporter implements StreamReporter {
String text = "Global error " + err.getErrorId();
globalErrors.add10PtTextElement(text, 10);
if (err instanceof SchematronError) {
text = ((SchematronError) err).getText();
globalErrors.add10PtTextElement(text, 20);
}
PdfErrorHandler handler = new PdfErrorHandler(globalErrors, config.getParserConfiguration());
err.report(handler);
}
@Override
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment