Commit b9d7b793 authored by Luna Riegel's avatar Luna Riegel
Browse files

Refactor: Remove Zip file support

parent 1310568f
Pipeline #12076 failed with stage
in 58 seconds
package de.hft.stuttgart.citydoctor2.database; package de.hft.stuttgart.citydoctor2.database;
import de.hft.stuttgart.citydoctor2.datastructure.CityObject;
import de.hft.stuttgart.citydoctor2.datastructure.GmlId; import de.hft.stuttgart.citydoctor2.datastructure.GmlId;
import de.hft.stuttgart.citydoctor2.parser.InvalidGmlFileException;
import de.hft.stuttgart.citydoctor2.zip.CityGmlZipEntry;
import org.apache.commons.io.FilenameUtils;
import java.io.File;
import java.util.List; import java.util.List;
public class CacheManager { public class CacheManager {
...@@ -23,10 +19,6 @@ public class CacheManager { ...@@ -23,10 +19,6 @@ public class CacheManager {
return cache; return cache;
} }
public static List<CityObject> retrieveLibraryObject(CityGmlZipEntry entry) throws InvalidGmlFileException {
return entry.getModel().getCache().retrieveLibraryObject(entry.getDisplayName());
}
public static void finishParsing(){ public static void finishParsing(){
if (cache != null){ if (cache != null){
cache.finishParsing(); cache.finishParsing();
......
...@@ -2,7 +2,6 @@ package de.hft.stuttgart.citydoctor2.database; ...@@ -2,7 +2,6 @@ package de.hft.stuttgart.citydoctor2.database;
import de.hft.stuttgart.citydoctor2.datastructure.CityObject; import de.hft.stuttgart.citydoctor2.datastructure.CityObject;
import de.hft.stuttgart.citydoctor2.datastructure.GmlId; import de.hft.stuttgart.citydoctor2.datastructure.GmlId;
import de.hft.stuttgart.citydoctor2.parser.InvalidGmlFileException;
import java.util.List; import java.util.List;
import java.util.stream.Stream; import java.util.stream.Stream;
...@@ -22,7 +21,4 @@ public interface CityObjectCache { ...@@ -22,7 +21,4 @@ public interface CityObjectCache {
void resetCache(); void resetCache();
List<CityObject> retrieveLibraryObject(String fileName) throws InvalidGmlFileException;
} }
...@@ -120,19 +120,6 @@ public class FeatureCache implements CityObjectCache{ ...@@ -120,19 +120,6 @@ public class FeatureCache implements CityObjectCache{
parsingFinished = false; parsingFinished = false;
} }
@Override
public List<CityObject> retrieveLibraryObject(String fileName) throws InvalidGmlFileException {
int featureCount = getTotalFeatureCount();
if (featureCount != 1){
if (featureCount == 0){
throw new InvalidGmlFileException(String.format("LibraryObject ZIP-entry %s contains no Feature", fileName));
} else {
throw new InvalidGmlFileException(String.format("LibraryObject ZIP-entry %s contains more than one Feature", fileName));
}
}
List<CityObject> objects = handler.getAllCityObjects();
return objects;
}
public void finishParsing() { public void finishParsing() {
if (!parsingFinished) { if (!parsingFinished) {
......
...@@ -48,9 +48,4 @@ public class UnconnectedCache implements CityObjectCache{ ...@@ -48,9 +48,4 @@ public class UnconnectedCache implements CityObjectCache{
public void resetCache(){ public void resetCache(){
// //
} }
@Override
public List<CityObject> retrieveLibraryObject(String fileName) throws InvalidGmlFileException {
return List.copyOf(cache.values());
}
} }
package de.hft.stuttgart.citydoctor2.datastructure; package de.hft.stuttgart.citydoctor2.datastructure;
import de.hft.stuttgart.citydoctor2.database.CacheManager;
import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException; import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException;
import de.hft.stuttgart.citydoctor2.parser.CityGmlParser; import de.hft.stuttgart.citydoctor2.parser.CityGmlParser;
import de.hft.stuttgart.citydoctor2.parser.InvalidGmlFileException; import de.hft.stuttgart.citydoctor2.parser.InvalidGmlFileException;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration; import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
import de.hft.stuttgart.citydoctor2.zip.CityGmlZipEntry;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
...@@ -45,22 +43,6 @@ public class LibraryObject extends Geometry { ...@@ -45,22 +43,6 @@ public class LibraryObject extends Geometry {
return libOb; return libOb;
} }
public static LibraryObject of(CityGmlZipEntry entry, ParserConfiguration config) {
String fileName = entry.getEntrySubPath();
if (libraryObjects.containsKey(fileName)){
return libraryObjects.get(fileName);
}
Geometry protoGeom = parseZipEntry(entry, config);
if (protoGeom == null) {
return null;
}
LibraryObject libOb = new LibraryObject(protoGeom.getType(), protoGeom.getLod(), protoGeom.getOrientation());
protoGeom.getPolygons().forEach(libOb::addPolygon);
libOb.updateEdgesAndVertices();
libraryObjects.put(fileName, libOb);
return libOb;
}
private LibraryObject(GeometryType type, Lod lod, Orientation orientation) { private LibraryObject(GeometryType type, Lod lod, Orientation orientation) {
super(type, lod, orientation); super(type, lod, orientation);
} }
...@@ -72,6 +54,7 @@ public class LibraryObject extends Geometry { ...@@ -72,6 +54,7 @@ public class LibraryObject extends Geometry {
try { try {
geo = getProtoGeometry(CityGmlParser.nestedCityGmlFileParse(path.toString(), config)); geo = getProtoGeometry(CityGmlParser.nestedCityGmlFileParse(path.toString(), config));
} catch (CityGmlParseException e) { } catch (CityGmlParseException e) {
//TODO: Localize Strings
logger.error(String.format( logger.error(String.format(
"Encountered an error while parsing library object %s", path)); "Encountered an error while parsing library object %s", path));
logger.error(e.getStackTrace()); logger.error(e.getStackTrace());
...@@ -79,50 +62,27 @@ public class LibraryObject extends Geometry { ...@@ -79,50 +62,27 @@ public class LibraryObject extends Geometry {
logger.error(e.getStackTrace()); logger.error(e.getStackTrace());
} }
} else { } else {
//TODO: Localize Strings
logger.error(String.format("Implicit geometry references non-existing library object file %s.", path)); logger.error(String.format("Implicit geometry references non-existing library object file %s.", path));
} }
return geo; return geo;
} }
private static Geometry parseZipEntry(CityGmlZipEntry entry, ParserConfiguration config) {
Geometry geo = null;
try {
entry.loadEntry(config, true);
geo = getProtoGeometry(entry);
} catch (InvalidGmlFileException e) {
logger.error(e.getStackTrace());
} catch (CityGmlParseException e) {
logger.error(String.format(
"Encountered an error while parsing library object %s", entry.getEntrySubPath()));
logger.error(e.getStackTrace());
}
return geo;
}
private static Geometry getProtoGeometry(CityDoctorModel model) throws InvalidGmlFileException, CityGmlParseException { private static Geometry getProtoGeometry(CityDoctorModel model) throws InvalidGmlFileException, CityGmlParseException {
if (model == null) { if (model == null) {
//TODO: Localize Strings
throw new CityGmlParseException("CityDoctorModel of referenced LibraryObject is null"); throw new CityGmlParseException("CityDoctorModel of referenced LibraryObject is null");
} }
List<CityObject> objects = model.createFeatureStream().toList(); List<CityObject> objects = model.createFeatureStream().toList();
if (objects.isEmpty()) { if (objects.isEmpty()) {
//TODO: Localize Strings
throw new InvalidGmlFileException("Referenced library-object gml file does not contain any CityGML objects!"); throw new InvalidGmlFileException("Referenced library-object gml file does not contain any CityGML objects!");
} else if (objects.size() > 1) { } else if (objects.size() > 1) {
//TODO: Localize Strings
throw new InvalidGmlFileException("Referenced library-object gml file contains more than one CityGML object!"); throw new InvalidGmlFileException("Referenced library-object gml file contains more than one CityGML object!");
} }
return objects.get(0).getHighestLodGeometry(); return objects.get(0).getHighestLodGeometry();
} }
private static Geometry getProtoGeometry(CityGmlZipEntry entry) throws InvalidGmlFileException, CityGmlParseException {
if (entry.getModel() == null) {
throw new CityGmlParseException("CityDoctorModel of referenced LibraryObject is null");
}
List<CityObject> objects = CacheManager.retrieveLibraryObject(entry);
if (objects.isEmpty()) {
throw new InvalidGmlFileException("Referenced library-object gml file does not contain any CityGML objects!");
} else if (objects.size() > 1) {
throw new InvalidGmlFileException("Referenced library-object gml file contains more than one CityGML object!");
}
return objects.get(0).getHighestLodGeometry();
}
} }
...@@ -158,7 +158,6 @@ import de.hft.stuttgart.citydoctor2.datastructure.WaterObject; ...@@ -158,7 +158,6 @@ import de.hft.stuttgart.citydoctor2.datastructure.WaterObject;
import de.hft.stuttgart.citydoctor2.math.graph.KDTree; import de.hft.stuttgart.citydoctor2.math.graph.KDTree;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration; import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
import de.hft.stuttgart.citydoctor2.utils.Localization; import de.hft.stuttgart.citydoctor2.utils.Localization;
import de.hft.stuttgart.citydoctor2.zip.CityGmlZipEntry;
public class Citygml3FeatureMapper extends ObjectWalker { public class Citygml3FeatureMapper extends ObjectWalker {
...@@ -167,7 +166,6 @@ public class Citygml3FeatureMapper extends ObjectWalker { ...@@ -167,7 +166,6 @@ public class Citygml3FeatureMapper extends ObjectWalker {
private final CityDoctorModel model; private final CityDoctorModel model;
private final ParserConfiguration config; private final ParserConfiguration config;
private final Path directory; private final Path directory;
private final CityGmlZipEntry zipEntry;
private final double neighborDistance; private final double neighborDistance;
private Map<String, ConcretePolygon> polygonMap = new HashMap<>(); private Map<String, ConcretePolygon> polygonMap = new HashMap<>();
private Map<String, CompositeCollection> compositeMap = new HashMap<>(); private Map<String, CompositeCollection> compositeMap = new HashMap<>();
...@@ -183,19 +181,6 @@ public class Citygml3FeatureMapper extends ObjectWalker { ...@@ -183,19 +181,6 @@ public class Citygml3FeatureMapper extends ObjectWalker {
model = new CityDoctorModel(config, path.toFile()); model = new CityDoctorModel(config, path.toFile());
} }
neighborDistance = 1.8d / Math.pow(10, config.getNumberOfRoundingPlaces()); neighborDistance = 1.8d / Math.pow(10, config.getNumberOfRoundingPlaces());
zipEntry = null;
}
public Citygml3FeatureMapper(ParserConfiguration config, CityGmlZipEntry entry, boolean nested) {
this.config = config;
this.directory = null;
this.zipEntry = entry;
if (nested){
model = new CityDoctorModel(config, Path.of(entry.getEntrySubPath()).toFile(), CacheManager.getUnconnectedCache());
} else {
model = new CityDoctorModel(config, Path.of(entry.getEntrySubPath()).toFile());
}
neighborDistance = 1.8d / Math.pow(10, config.getNumberOfRoundingPlaces());
} }
public static void parseId(AbstractGML gml, GmlElement gmlElement) { public static void parseId(AbstractGML gml, GmlElement gmlElement) {
...@@ -1033,12 +1018,6 @@ public class Citygml3FeatureMapper extends ObjectWalker { ...@@ -1033,12 +1018,6 @@ public class Citygml3FeatureMapper extends ObjectWalker {
if (directory != null){ if (directory != null){
Path libraryObjectPath = directory.resolve(ig.getLibraryObject()); Path libraryObjectPath = directory.resolve(ig.getLibraryObject());
libObj = LibraryObject.of(libraryObjectPath, config); libObj = LibraryObject.of(libraryObjectPath, config);
} else {
String libraryObjectPath = ig.getLibraryObject();
Path loPath = zipEntry.resolveLibraryObjectPath(libraryObjectPath);
CityGmlZipEntry libEntry = zipEntry.getArchive().getEntry(loPath.toString());
libObj = LibraryObject.of(libEntry, config);
} }
if (libObj != null) { if (libObj != null) {
igh = new ImplicitGeometryHolder(ig, libObj); igh = new ImplicitGeometryHolder(ig, libObj);
......
...@@ -93,8 +93,6 @@ import de.hft.stuttgart.citydoctor2.mapper.citygml3.Citygml3FeatureMapper; ...@@ -93,8 +93,6 @@ import de.hft.stuttgart.citydoctor2.mapper.citygml3.Citygml3FeatureMapper;
import de.hft.stuttgart.citydoctor2.mapper.citygml3.GMLValidationHandler; import de.hft.stuttgart.citydoctor2.mapper.citygml3.GMLValidationHandler;
import de.hft.stuttgart.citydoctor2.math.Vector3d; import de.hft.stuttgart.citydoctor2.math.Vector3d;
import de.hft.stuttgart.citydoctor2.utils.Localization; import de.hft.stuttgart.citydoctor2.utils.Localization;
import de.hft.stuttgart.citydoctor2.zip.CityGmlZipEntry;
import de.hft.stuttgart.citydoctor2.zip.CityGmlZipEntryFile;
import de.hft.stuttgart.quality.QualityADEContext; import de.hft.stuttgart.quality.QualityADEContext;
import de.hft.stuttgart.quality.QualityADEModule; import de.hft.stuttgart.quality.QualityADEModule;
...@@ -284,117 +282,12 @@ public class CityGmlParser { ...@@ -284,117 +282,12 @@ public class CityGmlParser {
return readAndKeepFeatures(config, file, in, ois, verbose, nested); return readAndKeepFeatures(config, file, in, ois, verbose, nested);
} }
} catch (CityGMLReadException | IOException e) { } catch (CityGMLReadException | IOException e) {
//TODO: Localize String
throw new CityGmlParseException("Failed to read CityGML file", e); throw new CityGmlParseException("Failed to read CityGML file", e);
} }
} }
public static CityDoctorModel parseCityGmlZipEntry(CityGmlZipEntry entry, ParserConfiguration config,
ProgressListener l, boolean nested)
throws CityGmlParseException, InvalidGmlFileException, IOException {
CityGMLContext context = getContext();
if (config.getValidate()) {
try (CityGmlZipEntryFile entryFile = new CityGmlZipEntryFile(entry)) {
List<String> messages = validateStream(entryFile.getInputStream(), context);
if (!messages.isEmpty()) {
throw new InvalidGmlFileException("Invalid GML File. First error: \n" + messages.get(0));
}
} catch (Exception e) {
throw new CityGmlParseException(e);
}
}
return decompressAndParseCityGmlEntry(entry, config, l, context, nested);
}
public static CityDoctorModel decompressAndParseCityGmlEntry(CityGmlZipEntry entry, ParserConfiguration config,
ProgressListener l, CityGMLContext context, boolean nested)
throws CityGmlParseException {
try (CityGmlZipEntryFile entryFile = new CityGmlZipEntryFile(entry)) {
BufferedInputStream bis = new BufferedInputStream(entryFile.getInputStream());
readEpsgCodeFromInputStream(bis, config);
CityGMLInputFactory in = context.createCityGMLInputFactory()
.withChunking(ChunkOptions.chunkByProperties(chunkProperties).skipCityModel(false));
try (ObservedInputStream ois = new ObservedInputStream(bis, bis.available())) {
if (l != null) {
ois.addListener(l::updateProgress);
}
return readAndKeepFeatures(config, entry, in, ois, false, nested);
}
} catch (CityGMLReadException | IOException e) {
throw new CityGmlParseException("Failed to read CityGML file", e);
} catch (Exception e) {
throw new CityGmlParseException(e);
}
}
private static CityDoctorModel readAndKeepFeatures(ParserConfiguration config, CityGmlZipEntry entry,
CityGMLInputFactory inputFactory, ObservedInputStream ois,
boolean verbose, boolean nested)
throws CityGMLReadException {
return readAndKeepModel(new Citygml3FeatureMapper(config, entry, nested), inputFactory, ois, verbose);
}
private static List<String> validateStream(InputStream vis, CityGMLContext context) throws CityGmlParseException {
GMLValidationHandler handler = new GMLValidationHandler();
try {
BufferedInputStream bis = new BufferedInputStream(vis);
SchemaHandler schemaHandler = new ValidationSchemaHandler(context.getDefaultSchemaHandler());
readAdditionalSchemaDefinitions(context, bis, schemaHandler);
Source[] schemas = schemaHandler.getSchemas();
SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
schemaFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
Schema schema = schemaFactory.newSchema(schemas);
Validator validator = schema.newValidator();
validator.setErrorHandler(handler);
validator.validate(new StreamSource(bis));
return handler.getMessages();
} catch (SchemaHandlerException | SAXException | IOException e) {
throw new CityGmlParseException("Failed to validate CityGML file", e);
}
}
private static void readAdditionalSchemaDefinitions(CityGMLContext context, BufferedInputStream bis, SchemaHandler schemaHandler)
throws CityGmlParseException {
bis.mark(Integer.MAX_VALUE);
try (XMLReader reader = XMLReaderFactory.newInstance(context.getXMLObjects())
.withSchemaHandler(schemaHandler)
.createReader(bis)) {
reader.nextTag();
bis.reset();
} catch (Exception e) {
throw new CityGmlParseException("Failed to read Schema from stream.", e);
}
}
private static void readEpsgCodeFromInputStream(BufferedInputStream bis, ParserConfiguration config) throws CityGmlParseException {
try {
// Mark start position of GML-"file"
bis.mark(Integer.MAX_VALUE);
// Buffer the first 10000 chars of the Stream, EPSG/envelope info should be found within that range
int peekingWidth = Math.min(10000, bis.available());
byte[] buf = new byte[peekingWidth];
bis.read(buf, 0, peekingWidth);
bis.reset();
parseEpsgCodeFromBuffer(buf, config);
} catch (ParserConfigurationException | SAXException | IOException e) {
throw new CityGmlParseException("Failed to read CityGML file", e);
}
}
public static void streamCityGml(CityGmlZipEntry entry, ParserConfiguration config, CityGmlConsumer cityObjectConsumer,
String outputFile) throws CityGmlParseException, IOException {
try (CityGmlZipEntryFile entryFile = new CityGmlZipEntryFile(entry)) {
parseEpsgCodeFromStream(entryFile.getInputStream(), config);
startReadingCityGmlZipEntry(entry, config, null, cityObjectConsumer, outputFile);
} catch (ParserConfigurationException | SAXException | IOException e) {
throw new CityGmlParseException("Failed to read CityGML stream", e);
}
}
public static void streamCityGml(String file, ParserConfiguration config, CityGmlConsumer cityObjectConsumer, public static void streamCityGml(String file, ParserConfiguration config, CityGmlConsumer cityObjectConsumer,
String outputFile) throws CityGmlParseException { String outputFile) throws CityGmlParseException {
...@@ -452,26 +345,6 @@ public class CityGmlParser { ...@@ -452,26 +345,6 @@ public class CityGmlParser {
} }
private static void startReadingCityGmlZipEntry(CityGmlZipEntry entry, ParserConfiguration config, ProgressListener l,
CityGmlConsumer cityObjectConsumer, String outputFile) {
try (CityGmlZipEntryFile entryFile = new CityGmlZipEntryFile(entry);
ObservedInputStream ois = new ObservedInputStream(entryFile.getInputStream(), entry.getFileSize())) {
if (l != null) {
ois.addListener(l::updateProgress);
}
streamAndDiscardFeatures(entry, config, ois, cityObjectConsumer, outputFile);
} catch (IOException | CityGMLReadException e) {
logger.error(Localization.getText("CityGmlParser.errorReadingGmlFile"), e.getMessage());
logger.catching(Level.ERROR, e);
}
}
private static void streamAndDiscardFeatures(CityGmlZipEntry entry, ParserConfiguration config, ObservedInputStream ois,
CityGmlConsumer cityObjectConsumer, String outputFile) throws CityGMLReadException {
Citygml3FeatureMapper mapper = new Citygml3FeatureMapper(config, entry, false);
readAndDiscardModel(mapper, ois, cityObjectConsumer, outputFile);
}
private static void readAndDiscardModel(Citygml3FeatureMapper mapper, ObservedInputStream ois, private static void readAndDiscardModel(Citygml3FeatureMapper mapper, ObservedInputStream ois,
CityGmlConsumer cityObjectConsumer, String outputFile) throws CityGMLReadException { CityGmlConsumer cityObjectConsumer, String outputFile) throws CityGMLReadException {
getContext(); getContext();
......
package de.hft.stuttgart.citydoctor2.utils;
import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel;
import de.hft.stuttgart.citydoctor2.zip.CityGmlZipArchive;
import de.hft.stuttgart.citydoctor2.zip.CityGmlZipEntry;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
public class ArchivePacker {
private static final Logger logger = LogManager.getLogger(ArchivePacker.class);
private ArchivePacker(){}
public static void packArchive(String targetPath, CityGmlZipArchive archive){
Path outputPath = Path.of(targetPath);
outputPath = outputPath.getParent().resolve(
FilenameUtils.removeExtension(outputPath.getFileName().toString()) + ".zip");
Path tmpDir = null;
try{
tmpDir = Files.createTempDirectory("zipTmp");
tmpDir.toFile().deleteOnExit();
for (CityGmlZipEntry entry : archive.getEntries()) {
if (entry.getErrorType() != null || !entry.isLoaded()) {
continue;
}
CityDoctorModel model = entry.getModel();
Path filePath = tmpDir.resolve(entry.getEntrySubPath());
Files.createDirectories(filePath.getParent());
model.saveAs(filePath.toString(), model.isValidated());
}
zipFolder(tmpDir.toFile(), outputPath.toFile());
}catch (Exception e){
logger.error(e);
} finally {
if (tmpDir != null) {
try {
FileUtils.deleteDirectory(tmpDir.toFile());
} catch (IOException e) {
logger.error(e);
}
}
}
}
public static void zipFolder(File folder, File zipFile) throws IOException {
zipFolder(folder, new FileOutputStream(zipFile));
}
public static void zipFolder(File folder, OutputStream outputStream) throws IOException {
try (ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream)) {
processFolder(folder, zipOutputStream, folder.getPath().length() + 1);
}
}
private static void processFolder(File folder, ZipOutputStream zipOutputStream, int prefixLength)
throws IOException {
for (File file : folder.listFiles()) {
if (file.isFile()) {
ZipEntry zipEntry = new ZipEntry(file.getPath().substring(prefixLength));
zipOutputStream.putNextEntry(zipEntry);
try (FileInputStream inputStream = new FileInputStream(file)) {
IOUtils.copy(inputStream, zipOutputStream);
}
zipOutputStream.closeEntry();
} else if (file.isDirectory()) {
processFolder(file, zipOutputStream, prefixLength);
}
}
}
public static void packAndDeleteDirectory(String directoryPath) throws IOException {
Path sourcePath = Path.of(directoryPath);
if (!Files.exists(sourcePath)) {
throw new IllegalStateException("Directory " + directoryPath + " does not exist");
}
if (!Files.isDirectory(sourcePath)) {
throw new IllegalStateException("Path " + directoryPath + " is not a directory");
}
Path outputPath = sourcePath.getParent().resolve(sourcePath.getFileName() + ".zip");
zipFolder(sourcePath.toFile(), outputPath.toFile());
FileUtils.deleteDirectory(sourcePath.toFile());
}
}
package de.hft.stuttgart.citydoctor2.zip;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
import de.hft.stuttgart.citydoctor2.utils.ArchivePacker;
import de.hft.stuttgart.citydoctor2.utils.Localization;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.Serial;
import java.io.Serializable;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
/**
* This class serves as a representation of a ZIP-archive containing CityGml files. The contained files are represented
* by {@link CityGmlZipEntry} objects.
*/
public class CityGmlZipArchive implements Serializable {
private static final Logger logger = LogManager.getLogger(CityGmlZipArchive.class);
@Serial
private static final long serialVersionUID = 2168389511043362615L;
private List<CityGmlZipEntry> entries;
private final Path archivePath;
private final String archiveNameRE;
/**
* Registers a ZIP-file as an archive. All contained XML and GML files will be registered as {@link CityGmlZipEntry} objects.
*
* @param zipFile path of the ZIP-file
* @return A {@link CityGmlZipArchive} object representing the archive, or null if read-access for the ZIP-file was denied
* @throws MalformedZipFileException if the ZIP-file has encoding errors
*/
public static CityGmlZipArchive register(String zipFile) throws MalformedZipFileException {
ArrayList<CityGmlZipEntry> archiveEntries = new ArrayList<>();
CityGmlZipArchive cgmlArchive = new CityGmlZipArchive(Path.of(zipFile));
try (ZipInputStream zis = new ZipInputStream(new FileInputStream(zipFile))) {
ZipEntry ze;
while ((ze = zis.getNextEntry()) != null) {
if (ze.isDirectory()) {
continue;
}
if (ze.getName().endsWith(".gml") || ze.getName().endsWith(".xml")) {
// Ignore report files generated by CityDoctor
if (ze.getName().endsWith("_report.xml")) {
continue;
}
archiveEntries.add(CityGmlZipEntry.register(ze, cgmlArchive));
}
}
cgmlArchive.setEntries(archiveEntries);
return cgmlArchive;
} catch (IOException e) {
logger.error(Localization.getText("CityGmlZipArchive.ioError"));
logger.debug(e.getMessage(), e);
return null;
} catch (IllegalArgumentException e) {
logger.error(Localization.getText("CityGmlZipArchive.malformedZipFile"));
throw new MalformedZipFileException(Localization.getText("CityGmlZipArchive.malformedZipFile"));
} catch (Exception e) {
logger.error(Localization.getText("CityGmlZipArchive.generalException"));
logger.debug(e.getMessage(), e);
throw (e);
}
}
/**
* Attempts to load all contained {@link CityGmlZipEntry} objects into memory.
*
* @param config Parser configuration for the entries
*/
public void mountArchive(ParserConfiguration config) {
try (ZipFile zip = new ZipFile(archivePath.toFile())) {
for (CityGmlZipEntry entry : entries) {
entry.loadEntry(config);
}
} catch (IOException e) {
logger.error(e);
}
}
private CityGmlZipArchive(Path archivePath) {
this.archivePath = archivePath;
this.archiveNameRE = archivePath.getFileName().toString().replace(".zip", "") + File.separator;
}
private void setEntries(List<CityGmlZipEntry> entries) {
this.entries = entries;
}
/**
* Saves this archive as a ZIP-file.
* @param path target path for the export
*/
public void exportToZipFile(String path) {
ArchivePacker.packArchive(path, this);
}
/**
* Gets an entry in this archive by its subpath.
*
* @param subpath subpath to the entry from this archive's root directory
* @return the corresponding entry, or null if entry could not be found
*/
public CityGmlZipEntry getEntry(String subpath) {
subpath = stripArchivePath(subpath);
for (CityGmlZipEntry entry : entries) {
String entryName = stripArchivePath(entry.getEntrySubPath());
if (entryName.equals(subpath)) {
return entry;
}
}
return null;
}
/**
* Strips the root directory name of this archive from an entry subpath.
* @param path the relative path to the entry
* @return String of the path without the root directory
*/
private String stripArchivePath(String path) {
Path systemPath = Path.of(path);
return systemPath.toString().replace(archiveNameRE, "");
}
/**
* Gets the path to the ZIP-file associated with this archive.
* @return path of the ZIP-file
*/
public Path getArchivePath() {
return archivePath;
}
/**
* Gets the entry list of this archive.
* @return the entry list
*/
public List<CityGmlZipEntry> getEntries() {
return entries;
}
}
package de.hft.stuttgart.citydoctor2.zip;
import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel;
import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException;
import de.hft.stuttgart.citydoctor2.parser.CityGmlParser;
import de.hft.stuttgart.citydoctor2.parser.InvalidGmlFileException;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
import de.hft.stuttgart.citydoctor2.parser.ProgressListener;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.IOException;
import java.io.Serial;
import java.io.Serializable;
import java.nio.file.Path;
import java.util.zip.ZipEntry;
/**
* This class serves as a representation of a CityGml file in a ZIP archive.
* <p/>
* The {@link CityDoctorModel} of the associated file can only be accessed after loading the corresponding entry.
*/
public class CityGmlZipEntry implements Serializable {
private static final Logger logger = LogManager.getLogger(CityGmlZipEntry.class);
@Serial
private static final long serialVersionUID = -5732913269959043262L;
private final Path filePath;
private final String fileName;
private final String displayName;
private transient CityDoctorModel model;
private CityGmlZipArchive parentArchive;
private boolean inMemory;
private long fileSize = -1L;
private static final long MB = 1024 * 1024L;
private ZipEntryErrorType errorType = null;
/**
* Attempts to parse the CityGML model associated with this entry and loads it into memory.
* <p/>
* In the event of a parsing error, the entry will be flagged by assigning the appropriate
* {@link ZipEntryErrorType} to the errorType field.
*
* @param config Parser configuration for this model
*/
public void loadEntry(ParserConfiguration config) {
loadEntry(config, null, false);
}
public void loadEntry(ParserConfiguration config, boolean nested) {
loadEntry(config, null, nested);
}
public void loadEntry(ParserConfiguration config, ProgressListener progressListener) {
loadEntry(config, progressListener, false);
}
/**
* Attempts to parse the CityGML model associated with this entry and loads it into memory.
* <p/>
* In the event of a parsing error, the entry will be flagged by assigning the appropriate
* {@link ZipEntryErrorType} to the errorType field.
*
* @param config Parser configuration for this model
* @param l ProgressListener for tracking parsing progress
*/
public void loadEntry(ParserConfiguration config, ProgressListener l, boolean nested) {
if (inMemory) {
return;
}
if (errorType != null) {
logger.warn("Tried loading erroneous CityGmlZipEntry");
return;
}
try {
this.model = CityGmlParser.parseCityGmlZipEntry(this, config, l, nested);
this.inMemory = true;
} catch (CityGmlParseException | InvalidGmlFileException e) {
logger.error(e);
this.errorType = ZipEntryErrorType.INVALID_CITY_GML_FILE;
} catch (IOException e) {
logger.error(e);
this.errorType = ZipEntryErrorType.IO_ERROR;
}
}
/**
* Registers a {@link ZipEntry ZipEntry} in a ZIP-archive as a {@link CityGmlZipEntry}.
* <p/>
* If the filesize of the associated file exceeds the total available system memory, or read access is denied,
* the entry will be flagged by assigning the appropriate {@link ZipEntryErrorType} to the errorType field.
*
* @param entry The ZipEntry object
* @param parentArchive The parent archive for this entry
* @return A corresponding CityGmlZipEntry object
*/
public static CityGmlZipEntry register(ZipEntry entry, CityGmlZipArchive parentArchive) {
CityGmlZipEntry cgzEntry = new CityGmlZipEntry(entry, parentArchive, false);
try {
if (!cgzEntry.entrySizeWithinMemoryLimits()) {
cgzEntry.errorType = ZipEntryErrorType.EXCESSIVE_FILESIZE;
}
} catch (IOException e) {
logger.error(e);
cgzEntry.errorType = ZipEntryErrorType.IO_ERROR;
}
return cgzEntry;
}
/**
* Checks if the filesize of this entry would exceed the system's available memory.
*
* @return true if within limits, false otherwise
* @throws IOException if read access to the ZIP-archive is denied
*/
private boolean entrySizeWithinMemoryLimits() throws IOException {
long memoryLimit = (long) Math.ceil(((double) Runtime.getRuntime().maxMemory() / MB) * 0.9);
if (fileSize == -1L) {
try (CityGmlZipEntryFile entryFile = new CityGmlZipEntryFile(this)) {
long filesize = entryFile.getFileSize();
if (filesize != -1) {
this.fileSize = filesize;
} else {
return false;
}
} catch (Exception e) {
throw new IOException(e);
}
}
return memoryLimit > (fileSize / MB);
}
private CityGmlZipEntry(ZipEntry entry, CityGmlZipArchive parentArchive, boolean inMemory) {
this.fileName = entry.getName();
this.filePath = Path.of(entry.getName());
this.displayName = filePath.getFileName().toString();
if (entry.getSize() != -1) {
this.fileSize = entry.getSize();
}
this.model = null;
this.inMemory = inMemory;
this.parentArchive = parentArchive;
}
/**
* Gets the parent archive of this entry.
* @return the archive
*/
public CityGmlZipArchive getArchive() {
return parentArchive;
}
/**
* Gets the sub-path in the archive of the file associated with this entry.
*
* @return the relative sub-path from the archive root directory
*/
public String getEntrySubPath() {
return fileName;
}
/**
* Gets the name of the file associated with this entry.
* @return the filename
*/
public String getDisplayName() {
return displayName;
}
/**
* Gets the {@link ZipEntryErrorType} of this entry.
* @return the error type, or null if this entry is not erroneous
*/
public ZipEntryErrorType getErrorType() {
return errorType;
}
/**
* Gets the {@link CityDoctorModel} of this entry.
* @return The model, or null if the entry has not been loaded or is erroneous
*/
public CityDoctorModel getModel() {
return model;
}
public void setFileSize(long size) {
fileSize = size;
}
/**
* Resolves the reference path of a {@link de.hft.stuttgart.citydoctor2.datastructure.LibraryObject LibraryObject}
* in the {@link CityDoctorModel} of this entry.
* @param libraryObjectPath The reference path to the LibraryObject's CityGml file
* @return Relative sub-path within the archive to the CityGml file
*/
public Path resolveLibraryObjectPath(String libraryObjectPath) {
return filePath.getParent().resolve(libraryObjectPath);
}
/**
* Checks if the {@link CityDoctorModel} of this entry has been loaded into memory.
*
* @return true if it is loaded, false otherwise
*/
public boolean isLoaded() {
return inMemory;
}
/**
* Returns the estimated uncompressed filesize of this entry.
*
* @return filesize in bytes, -1L if filesize is unknown
*/
public long getFileSize() {
return fileSize;
}
}
package de.hft.stuttgart.citydoctor2.zip;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
/**
* This class serves as a resource for read-access to the file that is being represented by
* a CityGmlZipEntry object.
* <p/>
* Does not decompress the file or the parent ZIP-archive.
*/
public class CityGmlZipEntryFile implements AutoCloseable {
private final ZipFile zip;
private final ZipEntry zipEntry;
private final CityGmlZipEntry cgmlZipEntry;
private boolean closed = false;
/**
* Creates a {@link CityGmlZipEntryFile} for a {@link CityGmlZipEntry} object's referenced file.
*
* @param entry the requested entry
* @throws IOException if read access to the ZIP-archive is denied.
*/
public CityGmlZipEntryFile(CityGmlZipEntry entry) throws IOException {
CityGmlZipArchive archive = entry.getArchive();
zip = new ZipFile(archive.getArchivePath().toFile());
zipEntry = zip.getEntry(entry.getEntrySubPath());
this.cgmlZipEntry = entry;
}
/**
* Gets a new InputStream of this file.
* <p/>
* Returned streams are independent of each other, but will all be closed when the {@link CityGmlZipEntryFile} object
* is closed.
* @return an InputStream of this file.
* @throws IOException when this method is called after the file has been closed.
*/
public InputStream getInputStream() throws IOException {
if (closed){
throw new IOException("CityGmlZipEntryFile closed");
}
return zip.getInputStream(zipEntry);
}
/**
* Gets an estimation of this file's filesize.
* @return filesize in bytes, -1L if unknown
* @throws IOException when this method is called after the file has been closed.
*/
public long getFileSize() throws IOException {
if (closed){
throw new IOException("CityGmlZipEntryFile closed");
}
if (cgmlZipEntry.getFileSize() == -1L) {
if (zipEntry.getSize() == -1) {
long bytes = 0;
InputStream is = new BufferedInputStream(this.getInputStream());
for (int i = is.read(); i != -1; i = is.read()) {
bytes++;
}
cgmlZipEntry.setFileSize(bytes);
} else {
cgmlZipEntry.setFileSize(zipEntry.getSize());
}
}
return cgmlZipEntry.getFileSize();
}
@Override
public void close() throws IOException {
zip.close();
closed = true;
}
}
package de.hft.stuttgart.citydoctor2.zip;
import java.util.zip.ZipException;
/**
* Signals that a ZIP-file is corrupted and couldn't be parsed.
*/
public class MalformedZipFileException extends ZipException {
public MalformedZipFileException() {
super();
}
public MalformedZipFileException(String message) {
super(message);
}
}
package de.hft.stuttgart.citydoctor2.zip;
/**
* Error types for {@link CityGmlZipEntry} objects.
*/
public enum ZipEntryErrorType {
INVALID_CITY_GML_FILE, EXCESSIVE_FILESIZE, IO_ERROR
}
package de.hft.stuttgart.citydoctor2.zip;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class ZipParser {
private static final Logger logger = LogManager.getLogger(ZipParser.class);
}
...@@ -113,27 +113,6 @@ CheckDialog.outputPathBtn=Select ...@@ -113,27 +113,6 @@ CheckDialog.outputPathBtn=Select
CheckDialog.pdfReportsOption=Create PDF reports CheckDialog.pdfReportsOption=Create PDF reports
CheckDialog.xmlReportsOption=Create XML reports CheckDialog.xmlReportsOption=Create XML reports
CheckDialog.noPathError=Output path is missing! CheckDialog.noPathError=Output path is missing!
ZipEntryManager.title=Zip-entry manager
ZipEntryManager.entryListTitle=Zip-entries
ZipEntryManager.metadata=Metadata
ZipEntryManager.subpathLbl=Subpath:
ZipEntryManager.erroneousLbl=Erroneous:
ZipEntryManager.excessiveFileSize=Filesize exceeds memory
ZipEntryManager.invalidCityGml=Invalid CityGML file
ZipEntryManager.ioError=Unable to access file
ZipEntryManager.filesizeLbl=Filesize:
ZipEntryManager.validatedLbl=Validated:
ZipEntryManager.objectCountLbl=Object count:
ZipEntryManager.loadBtn=Load CityGML model
ZipEntryManager.decompressBtn=Unpack file
ZipEntryManager.decompressAllBtn=Unpack all files
ZipEntryManager.checkAllBtn=Check all files
ZipEntryManager.showReportBtn=Show error statistic
ZipEntryManager.saveBtn=Export validation results
ZipEntryManager.cancelBtn=Cancel
ZipEntryManager.unknownValue=N/A
ZipEntryManager.yes=Yes
ZipEntryManager.no=No
CityGmlZipArchive.ioError=Accessing the ZIP archive failed CityGmlZipArchive.ioError=Accessing the ZIP archive failed
CityGmlZipArchive.malformedZipFile=Parsing of ZIP archive aborted, ZIP file is malformed! CityGmlZipArchive.malformedZipFile=Parsing of ZIP archive aborted, ZIP file is malformed!
CityGmlZipArchive.generalException=Encountered an unexpected error while reading the ZIP archive CityGmlZipArchive.generalException=Encountered an unexpected error while reading the ZIP archive
......
...@@ -111,27 +111,6 @@ CheckDialog.outputPathBtn=Ausw\u00e4hlen ...@@ -111,27 +111,6 @@ CheckDialog.outputPathBtn=Ausw\u00e4hlen
CheckDialog.pdfReportsOption=PDF Berichte erstellen CheckDialog.pdfReportsOption=PDF Berichte erstellen
CheckDialog.xmlReportsOption=XML Berichte erstellen CheckDialog.xmlReportsOption=XML Berichte erstellen
CheckDialog.noPathError=Ausgabepfad wurde nicht gesetzt! CheckDialog.noPathError=Ausgabepfad wurde nicht gesetzt!
ZipEntryManager.title=Zipeintrag Manager
ZipEntryManager.entryListTitle=Zipeintr\u00e4ge
ZipEntryManager.metadata=Metadaten
ZipEntryManager.subpathLbl=Unterpfad:
ZipEntryManager.erroneousLbl=Fehlerhaft:
ZipEntryManager.excessiveFileSize=Datei zu gro\u00DF
ZipEntryManager.invalidCityGml=Ung\u00fcltige CityGML Datei
ZipEntryManager.ioError=Dateizugriff fehlgeschlagen
ZipEntryManager.filesizeLbl=Dateigr\u00f6\u00DFe:
ZipEntryManager.validatedLbl=Validiert:
ZipEntryManager.objectCountLbl=Objektanzahl:
ZipEntryManager.loadBtn=CityGML Modell laden
ZipEntryManager.decompressBtn=Datei entpacken
ZipEntryManager.decompressAllBtn=Alle Dateien entpacken
ZipEntryManager.checkAllBtn=Alle Dateien pr\u00fcfen
ZipEntryManager.showReportBtn=Fehlerstatistik anzeigen
ZipEntryManager.saveBtn=Validierungsergebnisse exportieren
ZipEntryManager.cancelBtn=Abbruch
ZipEntryManager.unknownValue=Unbekannt
ZipEntryManager.yes=Ja
ZipEntryManager.no=Nein
CityGmlZipArchive.ioError=Zugriff auf ZIP-Datei fehlgeschlagen CityGmlZipArchive.ioError=Zugriff auf ZIP-Datei fehlgeschlagen
CityGmlZipArchive.malformedZipFile=Einlesen des ZIP-Archivs abgebrochen, ZIP-Datei ist fehlerhaft! CityGmlZipArchive.malformedZipFile=Einlesen des ZIP-Archivs abgebrochen, ZIP-Datei ist fehlerhaft!
CityGmlZipArchive.generalException=Unerwarteter Fehler beim Einlesen des ZIP-Archivs CityGmlZipArchive.generalException=Unerwarteter Fehler beim Einlesen des ZIP-Archivs
......
...@@ -21,10 +21,8 @@ package de.hft.stuttgart.citydoctor2; ...@@ -21,10 +21,8 @@ package de.hft.stuttgart.citydoctor2;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Path;
import java.util.List; import java.util.List;
import de.hft.stuttgart.citydoctor2.zip.CityGmlZipArchive;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.citygml4j.core.ade.ADEException; import org.citygml4j.core.ade.ADEException;
...@@ -162,8 +160,6 @@ public class CityDoctorValidation { ...@@ -162,8 +160,6 @@ public class CityDoctorValidation {
} }
if (inputFile.getName().endsWith(".gml") || inputFile.getName().endsWith(".xml")) { if (inputFile.getName().endsWith(".gml") || inputFile.getName().endsWith(".xml")) {
startFileValidation(inputFile, xmlOutput, pdfOutput, config, outputFile); startFileValidation(inputFile, xmlOutput, pdfOutput, config, outputFile);
} else if (inputFile.getName().endsWith(".zip")) {
startZipValidation(input, xmlOutput, pdfOutput, config, outputFile);
} else { } else {
logger.error("Input file '{}' does not end with .gml or .xml and is not a zip archive.", input); logger.error("Input file '{}' does not end with .gml or .xml and is not a zip archive.", input);
System.exit(1); System.exit(1);
...@@ -201,29 +197,6 @@ public class CityDoctorValidation { ...@@ -201,29 +197,6 @@ public class CityDoctorValidation {
} }
} }
public static void startZipValidation(String inputZipFile, String xmlOutput, String pdfOutput,
ValidationConfiguration config, String outputFile) throws CityGmlParseException, IOException {
xmlOutput = toDirectoryPath(xmlOutput);
pdfOutput = toDirectoryPath(pdfOutput);
outputFile = toDirectoryPath(outputFile);
if (xmlOutput == null && pdfOutput == null && outputFile == null) {
logger.warn("No output locations specified, results of validation will not be saved");
}
CityGmlZipArchive archive = CityGmlZipArchive.register(inputZipFile);
Checker.streamCheck(archive, xmlOutput, pdfOutput, config, outputFile);
}
public static String toDirectoryPath(String input) {
if (input == null) {
return null;
}
String parentDirectory = Path.of(input).getParent().toString() + File.separator;
String name = Path.of(input).getFileName().toString().replaceFirst("\\..+", "") + File.separator;
File f = new File(parentDirectory + name);
f.mkdir();
return f.getPath() + File.separator;
}
public static String getPdfOutput(ArgumentParser argParser) { public static String getPdfOutput(ArgumentParser argParser) {
if (argParser.containsOption("pdfreport")) { if (argParser.containsOption("pdfreport")) {
List<String> reportFiles = argParser.getValues("pdfreport"); List<String> reportFiles = argParser.getValues("pdfreport");
......
...@@ -44,11 +44,7 @@ import de.hft.stuttgart.citydoctor2.reporting.XmlStreamReporter; ...@@ -44,11 +44,7 @@ import de.hft.stuttgart.citydoctor2.reporting.XmlStreamReporter;
import de.hft.stuttgart.citydoctor2.reporting.XmlValidationReporter; import de.hft.stuttgart.citydoctor2.reporting.XmlValidationReporter;
import de.hft.stuttgart.citydoctor2.reporting.pdf.PdfReporter; import de.hft.stuttgart.citydoctor2.reporting.pdf.PdfReporter;
import de.hft.stuttgart.citydoctor2.reporting.pdf.PdfStreamReporter; import de.hft.stuttgart.citydoctor2.reporting.pdf.PdfStreamReporter;
import de.hft.stuttgart.citydoctor2.utils.ArchivePacker;
import de.hft.stuttgart.citydoctor2.utils.Localization; import de.hft.stuttgart.citydoctor2.utils.Localization;
import de.hft.stuttgart.citydoctor2.zip.CityGmlZipArchive;
import de.hft.stuttgart.citydoctor2.zip.CityGmlZipEntry;
import de.hft.stuttgart.citydoctor2.zip.CityGmlZipEntryFile;
import de.hft.stuttgart.quality.model.enums.RequirementId; import de.hft.stuttgart.quality.model.enums.RequirementId;
import de.hft.stuttgart.quality.model.enums.TopLevelFeatureType; import de.hft.stuttgart.quality.model.enums.TopLevelFeatureType;
import de.hft.stuttgart.quality.model.properties.CheckingProperty; import de.hft.stuttgart.quality.model.properties.CheckingProperty;
...@@ -59,7 +55,6 @@ import de.hft.stuttgart.quality.model.properties.RequirementProperty; ...@@ -59,7 +55,6 @@ import de.hft.stuttgart.quality.model.properties.RequirementProperty;
import de.hft.stuttgart.quality.model.types.Checking; import de.hft.stuttgart.quality.model.types.Checking;
import de.hft.stuttgart.quality.model.types.Parameter; import de.hft.stuttgart.quality.model.types.Parameter;
import de.hft.stuttgart.quality.model.types.ValidationPlan; import de.hft.stuttgart.quality.model.types.ValidationPlan;
import org.apache.commons.io.FilenameUtils;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
...@@ -825,73 +820,6 @@ public class Checker { ...@@ -825,73 +820,6 @@ public class Checker {
return hasUnusedDependency; return hasUnusedDependency;
} }
public static void streamCheck(CityGmlZipArchive archive, String xmlDirectory, String pdfDirectory, ValidationConfiguration config,
String outputDirectory) throws IOException, CityGmlParseException {
streamCheck(archive, xmlDirectory, pdfDirectory, config, null, outputDirectory);
}
public static void streamCheck(CityGmlZipArchive archive, String xmlDirectory, String pdfDirectory, ValidationConfiguration config,
FeatureCheckedListener l, String outputDirectory) throws IOException, CityGmlParseException {
for (CityGmlZipEntry entry : archive.getEntries()) {
String entryName = FilenameUtils.removeExtension(entry.getDisplayName());
String xmlOutput = null;
String pdfOutput = null;
String outputFile = null;
if (xmlDirectory != null) {
xmlOutput = Path.of(xmlDirectory).resolve(entryName + "_report.xml").toString();
}
if (pdfDirectory != null) {
pdfOutput = Path.of(pdfDirectory).resolve(entryName + "_report.pdf").toString();
}
if (outputDirectory != null) {
outputFile = Path.of(outputDirectory).resolve(entryName + "_validated.gml").toString();
}
streamCheck(entry, xmlOutput, pdfOutput, config, l, outputFile);
}
if (outputDirectory != null) {
ArchivePacker.packAndDeleteDirectory(outputDirectory);
}
}
public static void streamCheck(CityGmlZipEntry entry, String xmlOutput, String pdfOutput, ValidationConfiguration config,
String outputFile) throws IOException, CityGmlParseException {
streamCheck(entry, xmlOutput, pdfOutput, config, null, outputFile);
}
public static void streamCheck(CityGmlZipEntry entry, String xmlOutput, String pdfOutput, ValidationConfiguration config,
FeatureCheckedListener l, String outputFile) throws IOException, CityGmlParseException {
try (BufferedOutputStream xmlBos = getXmlOutputMaybe(xmlOutput);
BufferedOutputStream pdfBos = getPdfOutputMaybe(pdfOutput)) {
Checker c = new Checker(config, null);
String fileName = entry.getEntrySubPath();
// create reporter if available
XmlStreamReporter xmlReporter = getXmlReporter(config, xmlBos, fileName);
PdfStreamReporter pdfReporter = getPdfReporter(config, pdfBos, fileName);
// execute schematron first
try (CityGmlZipEntryFile entryFile = new CityGmlZipEntryFile(entry)) {
SvrlContentHandler handler = executeSchematronValidationIfAvailable(config, entryFile.getInputStream());
CityGmlConsumer con = new StreamCityGmlConsumer(c, xmlReporter, pdfReporter, handler, config, l);
// parse and validate
CityGmlParser.streamCityGml(entry, config.getParserConfiguration(), con, outputFile);
// write reports if available
writeReport(xmlReporter);
writeReport(pdfReporter);
}
} catch (CheckReportWriteException e) {
logger.error(Localization.getText("Checker.failReports"), e);
}
}
public static void streamCheck(File inputFile, String xmlOutput, String pdfOutput, ValidationConfiguration config, public static void streamCheck(File inputFile, String xmlOutput, String pdfOutput, ValidationConfiguration config,
String outputFile) throws IOException, CityGmlParseException { String outputFile) throws IOException, CityGmlParseException {
streamCheck(inputFile, xmlOutput, pdfOutput, config, null, outputFile); streamCheck(inputFile, xmlOutput, pdfOutput, config, null, outputFile);
......
...@@ -128,76 +128,6 @@ public class CheckerTest { ...@@ -128,76 +128,6 @@ public class CheckerTest {
} }
} }
@Test
public void testCliZipChecking() throws IOException, CityDoctorWriteException, CityGmlParseException, InvalidGmlFileException {
String output = folder.getRoot().toPath() + File.separator + "test";
String pdfOutput = folder.getRoot().toPath() + File.separator + "pdf" + File.separator;
String xmlOutput = folder.getRoot().toPath() + File.separator + "xml" + File.separator;
try {
String[] args = new String[10];
args[0] = "-in";
args[1] = "src/test/resources/zipArchive.zip";
args[2] = "-config";
args[3] = "src/test/resources/testConfigWithStreaming.yml";
args[4] = "-pdfReport";
args[5] = pdfOutput;
args[6] = "-xmlReport";
args[7] = xmlOutput;
args[8] = "-out";
args[9] = output + File.separator;
CityDoctorValidation.main(args);
File zipFile = new File(output + ".zip");
File pdfDir = new File(pdfOutput);
File xmlDir = new File(xmlOutput);
assertTrue(zipFile.exists());
assertTrue(pdfDir.exists());
assertTrue(xmlDir.exists());
assertTrue(pdfDir.isDirectory());
assertTrue(xmlDir.isDirectory());
assertEquals(5, pdfDir.listFiles().length);
assertEquals(5, xmlDir.listFiles().length);
CityGmlZipArchive cgmlArch = CityGmlZipArchive.register(output + ".zip");
assertNotNull(cgmlArch);
cgmlArch.mountArchive(new ParserConfiguration(8, true));
assertEquals(5, cgmlArch.getEntries().size());
for (CityGmlZipEntry entry : cgmlArch.getEntries()) {
assertNotNull(entry);
assertNull(entry.getErrorType());
}
} catch (CityGmlParseException | IOException | InvalidGmlFileException | CityDoctorWriteException e) {
throw e;
}
}
@Test
public void testZipEntryChecking() throws CityGmlParseException, IOException {
CityGmlZipArchive cgmlArch = CityGmlZipArchive.register("src/test/resources/zipArchive.zip");
assertNotNull(cgmlArch);
cgmlArch.mountArchive(new ParserConfiguration(8, false));
ValidationConfiguration config = ValidationConfiguration.loadStandardValidationConfig();
FeatureCheckedListener l = co -> {
assertTrue("CityObject should be validated", co.isValidated());
};
for (CityGmlZipEntry entry : cgmlArch.getEntries()) {
Checker.streamCheck(entry, null, null, config, l, null);
}
}
@Test
public void testZipArchiveChecking() throws CityGmlParseException, IOException {
CityGmlZipArchive cgmlArch = CityGmlZipArchive.register("src/test/resources/zipArchive.zip");
assertNotNull(cgmlArch);
cgmlArch.mountArchive(new ParserConfiguration(8, false));
ValidationConfiguration config = ValidationConfiguration.loadStandardValidationConfig();
FeatureCheckedListener l = co -> {
assertTrue(co.isValidated());
};
Checker.streamCheck(cgmlArch, null, null, config, l, null);
}
@Test @Test
public void testReportCreation() throws IOException, CityGmlParseException, InvalidGmlFileException { public void testReportCreation() throws IOException, CityGmlParseException, InvalidGmlFileException {
Path tmpDir = null; Path tmpDir = null;
......
...@@ -139,8 +139,6 @@ public class CheckDialog { ...@@ -139,8 +139,6 @@ public class CheckDialog {
@FXML @FXML
private Label schematronFileLabel; private Label schematronFileLabel;
@FXML
private VBox zipArchiveOptionsVBox;
@FXML @FXML
private CheckBox streamCheckOption; private CheckBox streamCheckOption;
@FXML @FXML
...@@ -161,7 +159,6 @@ public class CheckDialog { ...@@ -161,7 +159,6 @@ public class CheckDialog {
private CityDoctorController controller; private CityDoctorController controller;
private FilterPane filterPane; private FilterPane filterPane;
private MainWindow window; private MainWindow window;
private boolean zipArchiveMode;
public CheckDialog(MainWindow window, Window parent, CityDoctorController controller) throws IOException { public CheckDialog(MainWindow window, Window parent, CityDoctorController controller) throws IOException {
this.window = window; this.window = window;
...@@ -181,7 +178,6 @@ public class CheckDialog { ...@@ -181,7 +178,6 @@ public class CheckDialog {
} }
public void initialize() { public void initialize() {
setupZipArchiveOptions();
createEnableColumn(geometricTable); createEnableColumn(geometricTable);
createNameColumn(geometricTable); createNameColumn(geometricTable);
...@@ -286,46 +282,6 @@ public class CheckDialog { ...@@ -286,46 +282,6 @@ public class CheckDialog {
}); });
} }
private void setupZipArchiveOptions() {
streamCheckOption.selectedProperty().addListener(new ChangeListener<Boolean>() {
@Override
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
streamCheckParametersVBox.setDisable(!streamCheckOption.isSelected());
}
});
outputPathBtn.setOnAction(e -> {
DirectoryChooser directoryChooser = new DirectoryChooser();
directoryChooser.setInitialDirectory(Path.of(Settings.get(Settings.LAST_OPEN_FOLDER)).getParent().toFile());
File f = directoryChooser.showDialog(stage.getOwner());
if (f != null) {
outputPathTextField.setText(f.getAbsolutePath());
Settings.set(Settings.LAST_OPEN_FOLDER, f.getAbsolutePath());
}
});
streamCheckOption.setText(Localization.getText("CheckDialog.streamCheckOption"));
streamCheckLabel.setTooltip(new Tooltip(Localization.getText("CheckDialog.streamCheckLabel")));
outputPathLabel.setText(Localization.getText("CheckDialog.outputPathLabel"));
outputPathBtn.setText(Localization.getText("CheckDialog.outputPathBtn"));
pdfReportsOption.setText(Localization.getText("CheckDialog.pdfReportsOption"));
xmlReportsOption.setText(Localization.getText("CheckDialog.xmlReportsOption"));
showZipArchiveOptions(false);
}
/**
* Shows the option panel for ZIP-Archive checking and enables the ZIP-Archive checking mode for this dialog.
*
* @param enabled
*/
public void showZipArchiveOptions(boolean enabled) {
zipArchiveOptionsVBox.setDisable(!enabled);
zipArchiveOptionsVBox.setVisible(enabled);
zipArchiveMode = enabled;
}
private void setupSelectButton() { private void setupSelectButton() {
selectBtn.setOnAction(ae -> { selectBtn.setOnAction(ae -> {
...@@ -494,25 +450,7 @@ public class CheckDialog { ...@@ -494,25 +450,7 @@ public class CheckDialog {
String startingChecks = Localization.getText("CheckDialog.startingChecks"); String startingChecks = Localization.getText("CheckDialog.startingChecks");
logger.info(startingChecks); logger.info(startingChecks);
} }
if (zipArchiveMode) {
Path outputPath = null;
if (streamCheckOption.isSelected()) {
if (outputPathTextField.getText().isEmpty()) {
Alert warning = new Alert(Alert.AlertType.ERROR);
warning.setTitle("Error");
warning.setContentText(Localization.getText("CheckDialog.noPathError"));
warning.showAndWait();
return;
}
outputPath = Path.of(outputPathTextField.getText());
Platform.runLater(() -> progress.setProgress(ProgressIndicator.INDETERMINATE_PROGRESS));
}
controller.startZipFileChecks(config, progress::setProgress, streamCheckOption.isSelected(),
outputPath, pdfReportsOption.isSelected(),
xmlReportsOption.isSelected());
} else {
controller.startChecks(config, progress::setProgress); controller.startChecks(config, progress::setProgress);
}
if (logger.isInfoEnabled()) { if (logger.isInfoEnabled()) {
String checksDone = Localization.getText("CheckDialog.checksDone"); String checksDone = Localization.getText("CheckDialog.checksDone");
......
Supports Markdown
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