Commit 5d40c7b6 authored by Matthias Betz's avatar Matthias Betz
Browse files

CityDoctor2 validation open source release

parents
/*-
* 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.parser;
import static org.junit.Assert.*;
import org.junit.Test;
import org.osgeo.proj4j.CRSFactory;
import org.osgeo.proj4j.CoordinateReferenceSystem;
/**
*
* @author Matthias Betz
*
*/
public class ParserConfigurationTest {
@Test
public void testSetCoordinateSystem() {
ParserConfiguration config = new ParserConfiguration(0, false);
CRSFactory CRS_FACTORY = new CRSFactory();
CoordinateReferenceSystem utm = CRS_FACTORY.createFromParameters("UTM", "+proj=utm +zone=" + 2 + " +south");
config.setCoordinateSystem(utm, utm);
assertSame(utm, config.getOriginalTransform().getSourceCRS());
assertSame(utm, config.getTargetTransform().getSourceCRS());
}
}
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>de.hft.stuttgart</groupId>
<artifactId>CityDoctorParent</artifactId>
<version>3.7.0-SNAPSHOT</version>
</parent>
<artifactId>CityDoctorValidation</artifactId>
<name>CityDoctorValidation</name>
<description>validation part of city doctor containg all checks</description>
<dependencies>
<dependency>
<groupId>de.hft.stuttgart</groupId>
<artifactId>CityDoctorModel</artifactId>
</dependency>
<dependency>
<groupId>de.hft.stuttgart</groupId>
<artifactId>CityDoctorCheckResult</artifactId>
</dependency>
<dependency>
<groupId>net.sf.saxon</groupId>
<artifactId>Saxon-HE</artifactId>
</dependency>
<dependency>
<groupId>org.citygml4j</groupId>
<artifactId>citygml4j</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.xmlgraphics</groupId>
<artifactId>fop</artifactId>
</dependency>
<dependency>
<groupId>org.jdom</groupId>
<artifactId>jdom2</artifactId>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
</dependency>
<dependency>
<groupId>org.locationtech.jts</groupId>
<artifactId>jts-core</artifactId>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>libs/</classpathPrefix>
<mainClass>
de.hft.stuttgart.citydoctor2.CityDoctorValidation
</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<appendAssemblyId>false</appendAssemblyId>
<finalName>${project.artifactId}-${project.version}</finalName>
<descriptors>
<descriptor>${project.basedir}/src/assembly/assembly.xml</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<id>create-archive</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
<assembly
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
<id>zip</id>
<formats>
<format>zip</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<dependencySets>
<dependencySet>
<outputDirectory>libs</outputDirectory>
<excludes>
<exclude>${project.groupId}:${project.artifactId}:jar:*</exclude>
</excludes>
</dependencySet>
</dependencySets>
<fileSets>
<fileSet>
<directory>./assets/</directory>
<useDefaultExcludes>true</useDefaultExcludes>
<outputDirectory>./assets</outputDirectory>
</fileSet>
<fileSet>
<directory>${project.build.directory}</directory>
<outputDirectory>/</outputDirectory>
<includes>
<include>${project.artifactId}-${project.version}.jar</include>
</includes>
</fileSet>
<fileSet>
<directory>${project.basedir}/src/assembly</directory>
<outputDirectory>/</outputDirectory>
<includes>
<include>start.bat</include>
<include>testConfigWithStreaming.yml</include>
<include>REKaiserwall.gml</include>
</includes>
<filtered>true</filtered>
</fileSet>
</fileSets>
</assembly>
\ No newline at end of file
java -jar ${project.artifactId}-${project.version}.jar -in REKaiserwall.gml -config testConfigWithStreaming.yml -xmlReport output.xml
pause
\ No newline at end of file
numberOfRoundingPlaces: 8
useStreaming: true
xmlValidation: false
checks:
C_GE_R_TOO_FEW_POINTS:
enabled: true
C_GE_R_NOT_CLOSED:
enabled: true
C_GE_R_DUPLICATE_POINT:
enabled: true
parameters:
# in m
minVertexDistance: 0.0001
C_GE_R_SELF_INTERSECTION:
enabled: true
parameters:
# in m
minVertexDistance: 0.0001
C_GE_S_MULTIPLE_CONNECTED_COMPONENTS:
enabled: true
C_GE_P_INTERIOR_DISCONNECTED:
enabled: true
C_GE_P_INTERSECTING_RINGS:
enabled: true
C_GE_P_NON_PLANAR:
enabled: true
parameters:
# one of ("distance", "angle", "both")
type: distance
# in m
distanceTolerance: 0.01
# in radian
angleTolerance: 0.1
C_GE_P_HOLE_OUTSIDE:
enabled: true
C_GE_P_ORIENTATION_RINGS_SAME:
enabled: true
C_GE_P_INNER_RINGS_NESTED:
enabled: true
C_GE_S_TOO_FEW_POLYGONS:
enabled: true
C_GE_S_NOT_CLOSED:
enabled: true
C_GE_S_NON_MANIFOLD_EDGE:
enabled: true
C_GE_S_POLYGON_WRONG_ORIENTATION:
enabled: true
C_GE_S_ALL_POLYGONS_WRONG_ORIENTATION:
enabled: true
C_GE_S_NON_MANIFOLD_VERTEX:
enabled: true
C_GE_S_SELF_INTERSECTION:
enabled: true
C_SEM_BS_NOT_CEILING:
enabled: false
C_SEM_BS_NOT_FLOOR:
enabled: false
C_SEM_BS_NOT_GROUND:
enabled: false
C_SEM_BS_IS_WALL:
enabled: false
\ No newline at end of file
/*-
* 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;
import java.text.MessageFormat;
import java.util.Locale;
import java.util.ResourceBundle;
/**
* Provides access to message strings in different languages.
*
* @author Matthias Betz - 12bema1bif@hft-stuttgart.de
* @version 1.0
*
*/
public class CDVMessages {
public static final String MISSING_SOURCE_FILE = "ArgumentParser.MissingSourceFile";
public static final String INVALID_PARAMETER = "ArgumentParser.InvalidParameter";
public static final String VERSION = "CityDoctorValidation.Version";
private static final String BUNDLE_NAME = "de.hft.stuttgart.citydoctor2.cdvmessages";
private static final ResourceBundle RESOURCE_BUNDLE;
static {
RESOURCE_BUNDLE = ResourceBundle.getBundle(BUNDLE_NAME, Locale.getDefault());
}
/**
* Gives the message string for the given key based on the default locale.
*
* @param key
* the key for the message
* @return localized message.
*/
public static String getString(String key) {
return RESOURCE_BUNDLE.getString(key);
}
/**
* Constructs a string out of the key and the given parameters with the
* MessageFormatter.
*
* @param key
* the key for the message
* @param params
* the parameters for the message
* @return the localized message with the parameters substituted.
* @see MessageFormat#format(String, Object...);
*/
public static String getString(String key, Object... params) {
String msg = getString(key);
return MessageFormat.format(msg, params);
}
private CDVMessages() {
}
}
/*-
* 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;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.List;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import de.hft.stuttgart.citydoctor2.check.Checker;
import de.hft.stuttgart.citydoctor2.check.ValidationConfiguration;
import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel;
import de.hft.stuttgart.citydoctor2.parameter.ArgumentParser;
import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
import de.hft.stuttgart.citydoctor2.parser.CityGmlParser;
import de.hft.stuttgart.citydoctor2.parser.InvalidGmlFileException;
/**
* The main class for starting the complete validation process. Parsing of
* console parameters also happens here.
*
* @author Matthias Betz
*
*/
public class CityDoctorValidation {
private static final Logger logger = LogManager.getLogger(CityDoctorValidation.class);
private CityDoctorValidation() {
}
/**
* Main entry point for the validation process. Parsing of command line
* parameters happens here, then the validation process is called.
*
* @param args command line parameters
* @throws InterruptedException When the reading thread gets interrupted.
* @throws IOException When an exception while writing the report
* files happens.
* @throws CityGmlParseException When an error while parsing the cityGML file
* happens.
* @throws InvalidGmlFileException If the cityGML file is not valid according to
* the cityGML schema.
*/
public static void main(String[] args)
throws CityGmlParseException, IOException, InterruptedException, InvalidGmlFileException {
ArgumentParser argParser = new ArgumentParser(args);
String inputFile = getInputFile(argParser);
String xmlOutput = getXmlOutput(argParser);
String pdfOutput = getPdfOutput(argParser);
ValidationConfiguration config = getValidationConfig(argParser);
startValidationProcess(inputFile, xmlOutput, pdfOutput, config);
}
/**
* Validates the cityGML input file with a standard validation configuration.
*
* @param inputFile The cityGML file which is validated
* @param xmlOutput The XML report file location. Can be null.
* @param pdfOutput The PDF report file location. Can be null.
* @throws InterruptedException When the reading thread gets interrupted.
* @throws IOException When an exception while writing the report
* files happens.
* @throws CityGmlParseException When an error while parsing the cityGML file
* happens.
* @throws InvalidGmlFileException If the cityGML file is not valid according to
* the cityGML schema.
*/
public static void validate(File inputFile, File xmlOutput, File pdfOutput)
throws InterruptedException, IOException, CityGmlParseException, InvalidGmlFileException {
validate(inputFile, xmlOutput, pdfOutput, null);
}
/**
* Validates the cityGML input file with a specified validation configuration.
*
* @param inputFile The cityGML file which is validated
* @param xmlOutput The XML report file location. Can be null.
* @param pdfOutput The PDF report file location. Can be null.
* @param validationConfigFile The validation configuration file location.
* @throws InterruptedException When the reading thread gets interrupted.
* @throws IOException When an exception while writing the report
* files happens.
* @throws CityGmlParseException When an error while parsing the cityGML file
* happens.
* @throws InvalidGmlFileException If the cityGML file is not valid according to
* the cityGML schema.
*/
public static void validate(File inputFile, File xmlOutput, File pdfOutput, File validationConfigFile)
throws InterruptedException, IOException, CityGmlParseException, InvalidGmlFileException {
ValidationConfiguration config;
if (validationConfigFile == null) {
config = ValidationConfiguration.loadStandardValidationConfig();
config.setUseStreaming(true);
} else {
config = ValidationConfiguration.loadValidationConfig(validationConfigFile.getAbsolutePath());
}
String xmlOutputPath = null;
if (xmlOutput != null) {
xmlOutputPath = xmlOutput.getAbsolutePath();
}
String pdfOutputPath = null;
if (pdfOutput != null) {
pdfOutputPath = pdfOutput.getAbsolutePath();
}
startValidationProcess(inputFile.getAbsolutePath(), xmlOutputPath, pdfOutputPath, config);
}
public static void startValidationProcess(String inputFile, String xmlOutput, String pdfOutput,
ValidationConfiguration config)
throws InterruptedException, IOException, CityGmlParseException, InvalidGmlFileException {
ParserConfiguration parserConfig = config.getParserConfiguration();
if (config.isUseStreaming()) {
Checker.streamCheck(CityGmlParser.streamCityGml(inputFile, parserConfig), xmlOutput, pdfOutput, config);
} else {
CityDoctorModel model = CityGmlParser.parseCityGmlFile(inputFile, parserConfig);
Checker c = new Checker(config, model);
c.runChecks(xmlOutput, pdfOutput, null);
}
}
public static String getPdfOutput(ArgumentParser argParser) {
if (argParser.containsOption("pdfreport")) {
List<String> reportFiles = argParser.getValues("pdfreport");
if (reportFiles.size() != 1) {
logger.error("Specify exactly one file as pdfReport");
System.exit(6);
}
return reportFiles.get(0);
}
return null;
}
public static String getXmlOutput(ArgumentParser argParser) {
if (argParser.containsOption("xmlreport")) {
List<String> reportFiles = argParser.getValues("xmlreport");
if (reportFiles.size() != 1) {
logger.error("Specify exactly one file as xmlReport");
System.exit(5);
}
return reportFiles.get(0);
}
return null;
}
private static ValidationConfiguration getValidationConfig(ArgumentParser argParser) throws FileNotFoundException {
return getValidationConfig(argParser, true);
}
public static ValidationConfiguration getValidationConfig(ArgumentParser argParser, boolean optional) throws FileNotFoundException {
if (argParser.containsOption("config")) {
List<String> configFiles = argParser.getValues("config");
if (configFiles.size() != 1) {
logger.error("Specify exactly one file as configuration");
System.exit(4);
}
return ValidationConfiguration.loadValidationConfig(configFiles.get(0));
} else {
if (optional) {
logger.warn("No configuration file given, loading default configuration");
return ValidationConfiguration.loadStandardValidationConfig();
} else {
logger.error("No configuration file specified with -config [FILE]");
System.exit(7);
return null;
}
}
}
@SuppressWarnings("unused")
private static String getOutputFile(ArgumentParser argParser, String inputFile) {
if (argParser.containsOption("out")) {
List<String> outFiles = argParser.getValues("out");
if (outFiles.size() != 1) {
logger.error("Specify exactly one file as output.");
System.exit(3);
}
return outFiles.get(0);
} else {
return inputFile.substring(0, inputFile.lastIndexOf('.')) + "_healed.gml";
}
}
private static String getInputFile(ArgumentParser argParser) {
return getInputFile(argParser, false);
}
public static String getInputFile(ArgumentParser argParser, boolean optional) {
String inputFile;
if (!argParser.containsOption("in")) {
if (optional) {
return null;
}
logger.error("No input file specified. (-in [FILE])");
System.exit(1);
}
List<String> inFiles = argParser.getValues("in");
if (inFiles.size() != 1) {
logger.error("Specify exactly one file as input.");
System.exit(2);
}
inputFile = inFiles.get(0);
return inputFile;
}
}
/*-
* 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;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
/**
* The configuration of a single check. A check can have parameters and be
* enabled or disabled.
*
* @author Matthias Betz
*
*/
public class CheckConfiguration implements Serializable {
private static final long serialVersionUID = -1258195428669813888L;
private boolean enabled;
private Map<String, String> parameters;
/**
* @return Whether this check is enabled
*/
public boolean isEnabled() {
return enabled;
}
/**
* @param enabled Enable or disable this check
*/
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
/**
* @return The parameters given for this check.
*/
public Map<String, String> getParameters() {
if (parameters == null) {
parameters = new HashMap<>();
}
return parameters;
}
/**
* @param parameters Sets the parameters of this check.
*/
public void setParameters(Map<String, String> parameters) {
this.parameters = parameters;
}
@Override
public String toString() {
return "CheckConfiguration [enabled=" + enabled + ", parameters=" + parameters + "]";
}
}
/*-
* 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;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.Stream;
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Source;
import javax.xml.transform.TransformerException;
import javax.xml.transform.URIResolver;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamSource;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.w3c.dom.Document;
import de.hft.stuttgart.citydoctor2.check.error.SchematronError;
import de.hft.stuttgart.citydoctor2.checkresult.utility.CheckReportWriteException;
import de.hft.stuttgart.citydoctor2.checks.CheckContainer;
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;
import de.hft.stuttgart.citydoctor2.parser.FeatureStream;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
import de.hft.stuttgart.citydoctor2.parser.ProgressListener;
import de.hft.stuttgart.citydoctor2.reporting.Reporter;
import de.hft.stuttgart.citydoctor2.reporting.StreamReporter;
import de.hft.stuttgart.citydoctor2.reporting.XmlStreamReporter;
import de.hft.stuttgart.citydoctor2.reporting.XmlValidationReporter;
import de.hft.stuttgart.citydoctor2.reporting.pdf.PdfReporter;
import de.hft.stuttgart.citydoctor2.reporting.pdf.PdfStreamReporter;
import net.sf.saxon.s9api.DOMDestination;
import net.sf.saxon.s9api.Destination;
import net.sf.saxon.s9api.Processor;
import net.sf.saxon.s9api.SAXDestination;
import net.sf.saxon.s9api.SaxonApiException;
import net.sf.saxon.s9api.XsltCompiler;
import net.sf.saxon.s9api.XsltExecutable;
import net.sf.saxon.s9api.XsltTransformer;
/**
* The main container class for checking. It contains the logic for validation,
* as well as contains the state of the checks performed.
*
* @author Matthias Betz
*
*/
public class Checker {
private static final Logger logger = LogManager.getLogger(Checker.class);
private ValidationConfiguration config;
private List<List<Check>> execLayers;
private List<Filter> includeFilters;
private List<Filter> excludeFilters;
private boolean isValidated = false;
private Checks checkConfig;
private CityDoctorModel model;
public Checker(CityDoctorModel model) {
this(ValidationConfiguration.loadStandardValidationConfig(), model);
}
public Checker(ValidationConfiguration config, CityDoctorModel model) {
this.model = model;
checkConfig = new Checks();
setValidationConfig(config);
}
public Checks getChecks() {
return checkConfig;
}
public CityDoctorModel getModel() {
return model;
}
/**
* Write the xml report for the given CityDoctorModel. If no report location is
* given or this checker has not validated anything, nothing is done.
*
* @param xmlOutput the output file location for the XML report. Can be null.
* @param model the model for which the report is written.
*/
public void writeXmlReport(String xmlOutput) {
if (!isValidated || xmlOutput == null) {
return;
}
File xmlFile = new File(xmlOutput);
if (xmlFile.getParentFile() != null) {
xmlFile.getParentFile().mkdirs();
}
Reporter reporter = new XmlValidationReporter();
try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(xmlFile.getAbsolutePath()))) {
reporter.writeReport(checkConfig, bos, model, config);
} catch (CheckReportWriteException | IOException e) {
logger.error("Failed to write XML Error Report.", e);
}
}
public void writePdfReport(String pdfOutput) {
if (!isValidated || pdfOutput == null) {
return;
}
File pdfFile = new File(pdfOutput);
if (pdfFile.getParentFile() != null) {
pdfFile.getParentFile().mkdirs();
}
Reporter reporter = new PdfReporter("assets/Logo.png");
try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(pdfFile.getAbsolutePath()))) {
reporter.writeReport(checkConfig, bos, model, config);
} catch (IOException | CheckReportWriteException e) {
logger.error("Failed to write PDF Report.", e);
}
}
public void runChecks() {
runChecks((ProgressListener) null);
}
public void runChecks(String xmlOutput) {
runChecks();
writeXmlReport(xmlOutput);
}
public void runChecks(String xmlOutput, String pdfOutput) {
runChecks();
writeXmlReport(xmlOutput);
writePdfReport(pdfOutput);
}
public void runChecks(String xmlOutput, String pdfOutput, ProgressListener l) {
runChecks(l);
writeXmlReport(xmlOutput);
writePdfReport(pdfOutput);
}
public void runChecks(ProgressListener l) {
if (config == null) {
config = ValidationConfiguration.loadStandardValidationConfig();
}
checkCityModel(model, l);
logger.info("Finished executing checks");
SvrlContentHandler handler = executeSchematronValidationIfAvailable(config, model.getFile());
if (handler != null) {
model.addGlobalErrors(handler.getGeneralErrors());
Map<String, Checkable> 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) {
// gml id reported by schematron was not found, add to general errors
model.addGlobalError(v);
} else {
checkable.addCheckResult(new CheckResult(CheckId.C_SEM_SCHEMATRON, ResultStatus.ERROR, v));
}
});
}
isValidated = true;
}
private static SvrlContentHandler executeSchematronValidationIfAvailable(ValidationConfiguration config,
File file) {
if (config.getSchematronFilePath() != null && !config.getSchematronFilePath().isEmpty()) {
logger.info("Starting Schematron validation");
Processor processor = new Processor(false);
XsltCompiler xsltCompiler = processor.newXsltCompiler();
xsltCompiler.setURIResolver(new URIResolver() {
@Override
public Source resolve(String href, String base) throws TransformerException {
return new StreamSource(Checker.class.getResourceAsStream(href));
}
});
try {
XsltExecutable includeExecutable = xsltCompiler
.compile(new StreamSource(Checker.class.getResourceAsStream("iso_dsdl_include.xsl")));
XsltTransformer includeTransformer = includeExecutable.load();
includeTransformer.setSource(new StreamSource(new File(config.getSchematronFilePath())));
XsltExecutable expandExecutable = xsltCompiler
.compile(new StreamSource(Checker.class.getResourceAsStream("iso_abstract_expand.xsl")));
XsltTransformer expandTransformer = expandExecutable.load();
includeTransformer.setDestination(expandTransformer);
XsltExecutable xslt2Executable = xsltCompiler
.compile(new StreamSource(Checker.class.getResourceAsStream("iso_svrl_for_xslt2.xsl")));
XsltTransformer xslt2Transformer = xslt2Executable.load();
expandTransformer.setDestination(xslt2Transformer);
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
Document doc = factory.newDocumentBuilder().newDocument();
DOMDestination domDestination = new DOMDestination(doc);
xslt2Transformer.setDestination(domDestination);
includeTransformer.transform();
XsltExecutable schematronExecutable = xsltCompiler.compile(new DOMSource(doc));
XsltTransformer schematronTransformer = schematronExecutable.load();
schematronTransformer.setSource(new StreamSource(file));
SvrlContentHandler handler = new SvrlContentHandler();
Destination dest = new SAXDestination(handler);
schematronTransformer.setDestination(dest);
schematronTransformer.transform();
logger.info("Finished Schematron validation");
return handler;
} catch (SaxonApiException | ParserConfigurationException e) {
logger.catching(e);
}
}
return null;
}
private void buildFilters() {
FilterConfiguration filterConfig = config.getFilter();
if (filterConfig == null) {
includeFilters = Collections.emptyList();
excludeFilters = Collections.emptyList();
return;
}
excludeFilters = buildExcludeFilters(filterConfig);
includeFilters = buildIncludeFilters(filterConfig);
}
private List<Filter> buildExcludeFilters(FilterConfiguration filterConfig) {
if (filterConfig == null) {
return Collections.emptyList();
}
ExcludeFilterConfiguration excludeConfig = filterConfig.getExclude();
if (excludeConfig == null) {
return Collections.emptyList();
} else {
List<Filter> filters = new ArrayList<>();
if (excludeConfig.getTypes() != null) {
for (FeatureType excludeType : excludeConfig.getTypes()) {
filters.add(new TypeFilter(excludeType));
}
}
if (excludeConfig.getIds() != null) {
for (String excludePattern : excludeConfig.getIds()) {
Filter f = new EqualsIgnoreCaseFilter(excludePattern);
filters.add(f);
}
}
return filters;
}
}
private List<Filter> buildIncludeFilters(FilterConfiguration filterConfig) {
if (filterConfig == null) {
return Collections.emptyList();
}
IncludeFilterConfiguration includeConfig = filterConfig.getInclude();
if (includeConfig == null) {
return Collections.emptyList();
} else {
List<Filter> filters = new ArrayList<>();
if (includeConfig.getTypes() != null) {
for (FeatureType includeType : includeConfig.getTypes()) {
filters.add(new TypeFilter(includeType));
}
}
if (includeConfig.getIds() != null) {
for (String includePattern : includeConfig.getIds()) {
Filter f = new EqualsIgnoreCaseFilter(includePattern);
filters.add(f);
}
}
return filters;
}
}
private void setValidationConfig(ValidationConfiguration config) {
if (config == null) {
throw new IllegalArgumentException("Validation configuration may not be null");
}
this.config = config;
buildFilters();
ParserConfiguration parserConfig = config.getParserConfiguration();
List<Check> checks = collectEnabledChecksAndInit(parserConfig, config);
execLayers = buildExecutionLayers(checks);
// model has not been validated against the new configuration
}
private List<Check> collectEnabledChecksAndInit(ParserConfiguration parserConfig, ValidationConfiguration config) {
List<Check> checks = new ArrayList<>();
for (Entry<CheckId, CheckConfiguration> e : config.getChecks().entrySet()) {
if (e.getValue().isEnabled()) {
Check c = checkConfig.getCheckForId(e.getKey());
// initialize checks with parameters
c.init(e.getValue().getParameters(), parserConfig);
checks.add(c);
}
}
return checks;
}
private void checkCityModel(CityDoctorModel model, ProgressListener l) {
Stream<CityObject> features = model.createFeatureStream();
float featureSum = model.getNumberOfFeatures();
// stupid lamda with final variable restrictions
int[] currentFeature = new int[1];
features.forEach(co -> {
// check every feature
executeChecksForCityObject(co);
if (l != null) {
currentFeature[0]++;
l.updateProgress(currentFeature[0] / featureSum);
}
});
}
private boolean filterObject(CityObject co) {
return isObjectIncluded(co, includeFilters, excludeFilters);
}
private boolean isObjectIncluded(CityObject co, List<Filter> includeFilters, List<Filter> excludeFilters) {
if (!includeFilters.isEmpty()) {
boolean include = false;
for (Filter f : includeFilters) {
if (f.matches(co)) {
include = true;
break;
}
}
if (!include) {
// not included, ignore
return false;
}
}
// check if object is excluded
for (Filter f : excludeFilters) {
if (f.matches(co)) {
// exclude object
return false;
}
}
return true;
}
/**
* Checks the city object if it has not been removed by the filters. The check
* result are stored into the city object itself.
*
* @param co the city object that is going to be checked
*/
private void executeChecksForCityObject(CityObject co) {
if (!filterObject(co)) {
return;
}
executeChecksForCheckable(co);
}
/**
* Executes all checks for the checkable. This will bypass the filters.
*
* @param co the checkable.
*/
public void executeChecksForCheckable(Checkable co) {
// throw away old results
co.clearAllContainedCheckResults();
logger.debug("Checking feature: {}", co);
for (int i = 0; i < execLayers.size(); i++) {
for (Check check : execLayers.get(i)) {
logger.trace("Executing check: {}", check.getCheckId());
co.accept(check);
}
}
}
private List<List<Check>> buildExecutionLayers(List<Check> checks) {
List<List<Check>> result = new ArrayList<>();
for (Check c : checks) {
int layer = getLayerDepthForCheck(c);
while (layer >= result.size()) {
result.add(new ArrayList<Check>());
}
List<Check> checkLayer = result.get(layer);
checkLayer.add(new CheckContainer(c));
}
return result;
}
private int getLayerDepthForCheck(Check c) {
if (c.getDependencies().isEmpty()) {
return 0;
}
HashSet<CheckId> checkedChecks = new HashSet<>();
return getLayerDepthForCheck(c, checkedChecks);
}
private int getLayerDepthForCheck(Check c, HashSet<CheckId> checkedChecks) {
checkedChecks.add(c.getCheckId());
if (c.getDependencies().isEmpty()) {
return 0;
}
int maxDepth = 0;
for (CheckId dependency : c.getDependencies()) {
maxDepth = Math.max(maxDepth, getLayerDepthForCheck(checkConfig.getCheckForId(dependency), checkedChecks));
}
return maxDepth + 1;
}
public static void streamCheck(FeatureStream stream, String xmlOutput, String pdfOutput,
ValidationConfiguration config) throws InterruptedException, IOException {
streamCheck(stream, xmlOutput, pdfOutput, config, "assets/Logo.png", null);
}
public static void streamCheck(FeatureStream stream, String xmlOutput, String pdfOutput,
ValidationConfiguration config, String logoLocation, FeatureCheckedListener l)
throws InterruptedException, IOException {
Checker c = new Checker(config, null);
try (BufferedOutputStream xmlBos = getXmlOutputMaybe(xmlOutput);
BufferedOutputStream pdfBos = getPdfOutputMaybe(pdfOutput)) {
XmlStreamReporter xmlReporter = null;
if (xmlOutput != null) {
xmlReporter = new XmlStreamReporter(xmlBos, stream.getFileName(), config);
}
PdfStreamReporter pdfReporter = null;
if (pdfOutput != null) {
pdfReporter = new PdfStreamReporter(pdfBos, stream.getFileName(), config, logoLocation);
}
CityObject co = null;
while ((co = stream.next()) != null) {
c.checkFeature(xmlReporter, pdfReporter, co);
if (l != null) {
l.featureChecked(co);
}
}
SvrlContentHandler handler = executeSchematronValidationIfAvailable(config, stream.getFile());
writeReport(xmlReporter, handler);
writeReport(pdfReporter, handler);
} catch (CheckReportWriteException e) {
logger.error("Failed to write reports.", e);
}
}
private static void writeReport(StreamReporter reporter, SvrlContentHandler handler)
throws CheckReportWriteException {
if (reporter != null) {
if (handler != null) {
for (SchematronError err : handler.getGeneralErrors()) {
reporter.reportGlobalError(err);
}
for (Entry<String, SchematronError> e : handler.getFeatureErrors().entrySet()) {
reporter.addError(e.getKey(), e.getValue());
}
}
reporter.finishReport();
}
}
private static BufferedOutputStream getPdfOutputMaybe(String pdfOutput) throws FileNotFoundException {
return pdfOutput != null ? new BufferedOutputStream(new FileOutputStream(pdfOutput)) : null;
}
private static BufferedOutputStream getXmlOutputMaybe(String xmlOutput) throws FileNotFoundException {
return xmlOutput != null ? new BufferedOutputStream(new FileOutputStream(xmlOutput)) : null;
}
private void checkFeature(XmlStreamReporter xmlReporter, PdfStreamReporter pdfReporter, CityObject co) {
logger.debug("Checking feature: {}", co);
executeChecksForCityObject(co);
if (xmlReporter != null) {
xmlReporter.report(co);
}
if (pdfReporter != null) {
pdfReporter.report(co);
}
}
}
/*-
* 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;
import java.util.Objects;
import de.hft.stuttgart.citydoctor2.datastructure.CityObject;
/**
* Filters features by their GML-ID while ignoring case.
*
* @author Matthias Betz
*
*/
public class EqualsIgnoreCaseFilter implements Filter {
private String id;
public EqualsIgnoreCaseFilter(String id) {
Objects.requireNonNull(id);
this.id = id;
}
@Override
public boolean matches(CityObject co) {
return id.equalsIgnoreCase(co.getGmlId().getGmlString());
}
}
/*-
* 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;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import de.hft.stuttgart.citydoctor2.datastructure.FeatureType;
public class ExcludeFilterConfiguration implements Serializable {
private static final long serialVersionUID = 5308380997654048837L;
private List<FeatureType> types;
private List<String> ids;
public List<FeatureType> getTypes() {
if (types == null) {
return new ArrayList<>();
}
return types;
}
public void setTypes(List<FeatureType> types) {
this.types = types;
}
public List<String> getIds() {
if (ids == null) {
ids = new ArrayList<>();
}
return ids;
}
public void setIds(List<String> ids) {
this.ids = ids;
}
}
/*-
* 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;
import de.hft.stuttgart.citydoctor2.datastructure.CityObject;
/**
* This is the filter interface for filtering features from processing or
* include specific objects.
*
* @author Matthias Betz
*
*/
public interface Filter {
/**
* Filters a city object
*
* @param co The city object
* @return true if the filter is valid for the object.
*/
public boolean matches(CityObject co);
}
/*-
* 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;
import java.io.Serializable;
/**
* Filter configuration container for the yaml configuration file. Has include
* and exclude filters.
*
* @author Matthias Betz
*
*/
public class FilterConfiguration implements Serializable {
private static final long serialVersionUID = 3344890310114546998L;
private ExcludeFilterConfiguration exclude;
private IncludeFilterConfiguration include;
public ExcludeFilterConfiguration getExclude() {
return exclude;
}
public void setExclude(ExcludeFilterConfiguration exclude) {
this.exclude = exclude;
}
public IncludeFilterConfiguration getInclude() {
return include;
}
public void setInclude(IncludeFilterConfiguration include) {
this.include = include;
}
}
/*-
* 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;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import de.hft.stuttgart.citydoctor2.datastructure.FeatureType;
/**
* Include filters for the yaml configuration file. Can be a list of feature IDs
* or a list of feature types, which should be included in the validation
* process.
*
* @author Matthias Betz
*
*/
public class IncludeFilterConfiguration implements Serializable {
private static final long serialVersionUID = 1840264505629236113L;
private List<FeatureType> types;
private List<String> ids;
public List<FeatureType> getTypes() {
if (types == null) {
types = new ArrayList<>();
}
return types;
}
public void setTypes(List<FeatureType> types) {
this.types = types;
}
public List<String> getIds() {
if (ids == null) {
ids = new ArrayList<>();
}
return ids;
}
public void setIds(List<String> ids) {
this.ids = ids;
}
}
/*-
* 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;
import java.util.regex.Pattern;
import de.hft.stuttgart.citydoctor2.datastructure.CityObject;
public class PatternFilter implements Filter {
private Pattern pattern;
public PatternFilter(String patternString) {
pattern = Pattern.compile(patternString);
}
@Override
public boolean matches(CityObject co) {
return pattern.matcher(co.getGmlId().getGmlString()).matches();
}
}
/*-
* 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;
import de.hft.stuttgart.citydoctor2.datastructure.CityObject;
import de.hft.stuttgart.citydoctor2.datastructure.FeatureType;
/**
* Filters the feature type of features
*
* @author Matthias Betz
*
*/
public class TypeFilter implements Filter {
private FeatureType type;
public TypeFilter(FeatureType type) {
this.type = type;
}
@Override
public boolean matches(CityObject co) {
return co.getFeatureType() == type;
}
}
/*-
* 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;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Map;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.Constructor;
import de.hft.stuttgart.citydoctor2.checks.CheckPrototype;
import de.hft.stuttgart.citydoctor2.checks.Checks;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
/**
* The validation configuration class represented in the yaml configuration
* file. Here configuration files can be loaded and written as well as filled
* with missing data, when the configuration file is not complete.
*
* @author Matthias Betz
*
*/
public class ValidationConfiguration implements Serializable {
private static final long serialVersionUID = -8020055032177740646L;
private static Logger logger = LogManager.getLogger(ValidationConfiguration.class);
private int numberOfRoundingPlaces = 8;
private String schematronFilePath = null;
private boolean xmlValidation = false;
private boolean useStreaming = false;
private FilterConfiguration filter;
private Map<CheckId, CheckConfiguration> checks;
private ParserConfiguration parserConfig;
public static ValidationConfiguration loadValidationConfig(String validationFile) throws FileNotFoundException {
return loadValidationConfig(new FileInputStream(validationFile));
}
public static ValidationConfiguration loadValidationConfig(InputStream stream) {
Yaml yaml = new Yaml(new Constructor(ValidationConfiguration.class));
ValidationConfiguration config = yaml.load(stream);
config.validateConfiguration();
return config;
}
public static ValidationConfiguration loadStandardValidationConfig() {
ValidationConfiguration config = new ValidationConfiguration();
config.checks = new EnumMap<>(CheckId.class);
for (CheckPrototype c : Checks.getCheckPrototypes()) {
CheckConfiguration cConfig = new CheckConfiguration();
cConfig.setEnabled(true);
if (!c.getDefaultParameter().isEmpty()) {
Map<String, String> paramMap = new HashMap<>();
for (DefaultParameter param : c.getDefaultParameter()) {
paramMap.put(param.getName(), param.getDefaultValue());
}
cConfig.setParameters(paramMap);
}
config.checks.put(c.getCheckId(), cConfig);
}
return config;
}
public void saveAs(File f) throws IOException {
DumperOptions options = new DumperOptions();
options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
Yaml yaml = new Yaml(options);
try (BufferedWriter bw = new BufferedWriter(new FileWriter(f))) {
yaml.dump(this, bw);
}
}
public boolean isXmlValidation() {
return xmlValidation;
}
public void setXmlValidation(boolean xmlValidation) {
this.xmlValidation = xmlValidation;
}
public String getSchematronFilePath() {
return schematronFilePath;
}
public void setSchematronFilePath(String schematronFilePath) {
this.schematronFilePath = schematronFilePath;
}
public boolean isUseStreaming() {
return useStreaming;
}
public void setUseStreaming(boolean useStreaming) {
this.useStreaming = useStreaming;
}
public FilterConfiguration getFilter() {
return filter;
}
public void setFilter(FilterConfiguration filter) {
this.filter = filter;
}
public Map<CheckId, CheckConfiguration> getChecks() {
if (checks == null) {
checks = new EnumMap<>(CheckId.class);
}
return checks;
}
public void setChecks(Map<CheckId, CheckConfiguration> checks) {
this.checks = checks;
}
public void validateConfiguration() {
for (CheckPrototype c : Checks.getCheckPrototypes()) {
// enable all checks that are missing in the validation config
checks.computeIfAbsent(c.getCheckId(), id -> {
CheckConfiguration cConfig = new CheckConfiguration();
cConfig.setEnabled(true);
return cConfig;
});
}
for (java.util.Map.Entry<CheckId, CheckConfiguration> e : checks.entrySet()) {
if (!e.getValue().isEnabled()) {
continue;
}
CheckPrototype c = Checks.getCheckPrototypeForId(e.getKey());
for (CheckId dep : c.getDependencies()) {
CheckConfiguration checkConfig = checks.get(dep);
if (!checkConfig.isEnabled()) {
checkConfig.setEnabled(true);
logger.warn("{} has been disabled but {} depends on it, reenabling", dep, c.getCheckId());
}
}
insertMissingParametersWithDefaultParameters(e, c);
}
if (schematronFilePath != null) {
File f = new File(schematronFilePath);
if (!f.exists() || !f.isFile()) {
schematronFilePath = null;
logger.warn("{} is not an existing file, disabling schematron check", f.getAbsolutePath());
}
}
}
private void insertMissingParametersWithDefaultParameters(java.util.Map.Entry<CheckId, CheckConfiguration> e,
CheckPrototype c) {
for (DefaultParameter param : c.getDefaultParameter()) {
String configuredValue = e.getValue().getParameters().get(param.getName());
if (configuredValue == null) {
e.getValue().getParameters().put(param.getName(), param.getDefaultValue());
}
}
}
public int getNumberOfRoundingPlaces() {
return numberOfRoundingPlaces;
}
public void setNumberOfRoundingPlaces(int numberOfRoundingPlaces) {
this.numberOfRoundingPlaces = numberOfRoundingPlaces;
}
public ParserConfiguration getParserConfiguration() {
if (parserConfig == null) {
parserConfig = new ParserConfiguration(numberOfRoundingPlaces, xmlValidation);
}
return parserConfig;
}
public void setParserConfiguration(ParserConfiguration parserConfig) {
this.parserConfig = parserConfig;
}
}
/*-
* 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.checks;
import java.util.List;
import java.util.Map;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import de.hft.stuttgart.citydoctor2.check.Check;
import de.hft.stuttgart.citydoctor2.check.CheckError;
import de.hft.stuttgart.citydoctor2.check.CheckId;
import de.hft.stuttgart.citydoctor2.check.CheckResult;
import de.hft.stuttgart.citydoctor2.check.CheckType;
import de.hft.stuttgart.citydoctor2.check.Checkable;
import de.hft.stuttgart.citydoctor2.check.DefaultParameter;
import de.hft.stuttgart.citydoctor2.check.ResultStatus;
import de.hft.stuttgart.citydoctor2.check.error.UnknownCheckError;
import de.hft.stuttgart.citydoctor2.datastructure.AbstractBuilding;
import de.hft.stuttgart.citydoctor2.datastructure.BoundarySurface;
import de.hft.stuttgart.citydoctor2.datastructure.BridgeObject;
import de.hft.stuttgart.citydoctor2.datastructure.Building;
import de.hft.stuttgart.citydoctor2.datastructure.BuildingInstallation;
import de.hft.stuttgart.citydoctor2.datastructure.BuildingPart;
import de.hft.stuttgart.citydoctor2.datastructure.CityObject;
import de.hft.stuttgart.citydoctor2.datastructure.Geometry;
import de.hft.stuttgart.citydoctor2.datastructure.LandObject;
import de.hft.stuttgart.citydoctor2.datastructure.LinearRing;
import de.hft.stuttgart.citydoctor2.datastructure.Opening;
import de.hft.stuttgart.citydoctor2.datastructure.Polygon;
import de.hft.stuttgart.citydoctor2.datastructure.TransportationObject;
import de.hft.stuttgart.citydoctor2.datastructure.Vegetation;
import de.hft.stuttgart.citydoctor2.datastructure.WaterObject;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
/**
* A check according to the decorator pattern for handling unexpected exceptions
* while performing the containing check. This will generate an error object for
* writing the the reports, and will not cause the checking process to halt.
*
* @author Matthias Betz
*
*/
public class CheckContainer extends Check {
private static Logger logger = LogManager.getLogger(CheckContainer.class);
private final Check check;
public CheckContainer(Check check) {
super(null);
this.check = check;
}
@Override
public void init(Map<String, String> parameters, ParserConfiguration config) {
check.init(parameters, config);
}
@Override
public CheckId getCheckId() {
return check.getCheckId();
}
@Override
public List<Class<? extends Checkable>> getApplicableToClasses() {
return check.getApplicableToClasses();
}
@Override
public boolean canExecute(Checkable c) {
return check.canExecute(c);
}
private void handleException(Exception e, Checkable c) {
logger.error("Unexpected exception while executing check: " + check.getCheckId(), e);
CheckError err = new UnknownCheckError(c, e, this);
CheckResult cr = new CheckResult(check.getCheckId(), ResultStatus.ERROR, err);
c.addCheckResult(cr);
}
@Override
public List<DefaultParameter> getDefaultParameter() {
return check.getDefaultParameter();
}
@Override
public List<CheckId> getDependencies() {
return check.getDependencies();
}
@Override
public void check(AbstractBuilding ab) {
try {
check.check(ab);
} catch (Exception e) {
handleException(e, ab);
}
}
@Override
public void check(BoundarySurface bs) {
try {
check.check(bs);
} catch (Exception e) {
handleException(e, bs);
}
}
@Override
public void check(BridgeObject b) {
try {
check.check(b);
} catch (Exception e) {
handleException(e, b);
}
}
@Override
public void check(Building b) {
try {
check.check(b);
} catch (Exception e) {
handleException(e, b);
}
}
@Override
public void check(BuildingInstallation bi) {
try {
check.check(bi);
} catch (Exception e) {
handleException(e, bi);
}
}
@Override
public void check(BuildingPart bp) {
try {
check.check(bp);
} catch (Exception e) {
handleException(e, bp);
}
}
@Override
public void check(CityObject co) {
try {
check.check(co);
} catch (Exception e) {
handleException(e, co);
}
}
@Override
public void check(Geometry g) {
try {
check.check(g);
} catch (Exception e) {
handleException(e, g);
}
}
@Override
public void check(LandObject lo) {
try {
check.check(lo);
} catch (Exception e) {
handleException(e, lo);
}
}
@Override
public void check(LinearRing lr) {
try {
check.check(lr);
} catch (Exception e) {
handleException(e, lr);
}
}
@Override
public void check(Opening o) {
try {
check.check(o);
} catch (Exception e) {
handleException(e, o);
}
}
@Override
public void check(Polygon p) {
try {
check.check(p);
} catch (Exception e) {
handleException(e, p);
}
}
@Override
public void check(TransportationObject to) {
try {
check.check(to);
} catch (Exception e) {
handleException(e, to);
}
}
@Override
public void check(Vegetation veg) {
try {
check.check(veg);
} catch (Exception e) {
handleException(e, veg);
}
}
@Override
public void check(WaterObject wo) {
try {
check.check(wo);
} catch (Exception e) {
handleException(e, wo);
}
}
@Override
public CheckType getType() {
return check.getType();
}
@Override
public Check createNewInstance() {
return check.createNewInstance();
}
}
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