diff --git a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/zip/CityGmlZipArchive.java b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/zip/CityGmlZipArchive.java index 0fdf8aa50d4689624af0bcec30cedbd312a45e86..be6e4cda33b7f24ea127a9f14ed48ae55fa21b27 100644 --- a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/zip/CityGmlZipArchive.java +++ b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/zip/CityGmlZipArchive.java @@ -18,6 +18,10 @@ 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); @@ -29,7 +33,13 @@ public class CityGmlZipArchive implements Serializable { 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)); @@ -40,6 +50,7 @@ public class CityGmlZipArchive implements Serializable { continue; } if (ze.getName().endsWith(".gml") || ze.getName().endsWith(".xml")) { + // Ignore report files generated by CityDoctor if (ze.getName().endsWith("_report.xml")) { continue; } @@ -62,6 +73,11 @@ public class CityGmlZipArchive implements Serializable { } } + /** + * 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) { @@ -79,34 +95,55 @@ public class CityGmlZipArchive implements Serializable { private void setEntries(List<CityGmlZipEntry> entries) { this.entries = entries; - entries.forEach(e -> e.setArchive(this)); } + /** + * Saves this archive as a ZIP-file. + * @param path target path for the export + */ public void exportToZipFile(String path) { ArchivePacker.packArchive(path, this); } - - public CityGmlZipEntry getEntry(String fileName) { - fileName = stripArchivePath(fileName); + /** + * 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(fileName)) { + 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; } diff --git a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/zip/CityGmlZipEntry.java b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/zip/CityGmlZipEntry.java index 6c443bdcb02cf9e5ff4b6d343b710b8d6245d934..d9a86770b90e4f6e5703bf1a31adfda17080d9bd 100644 --- a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/zip/CityGmlZipEntry.java +++ b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/zip/CityGmlZipEntry.java @@ -15,6 +15,11 @@ 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); @@ -31,16 +36,28 @@ public class CityGmlZipEntry implements Serializable { private static final long MB = 1024 * 1024L; private ZipEntryErrorType errorType = null; - public static CityGmlZipEntry of(ZipEntry entry, CityGmlZipArchive parentArchive, ParserConfiguration config) { - CityGmlZipEntry ze = CityGmlZipEntry.register(entry, parentArchive); - ze.loadEntry(config); - return ze; - } + /** + * 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); } + /** + * 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) { if (inMemory) { return; @@ -61,6 +78,16 @@ public class CityGmlZipEntry implements Serializable { } } + /** + * 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 { @@ -74,6 +101,12 @@ public class CityGmlZipEntry implements Serializable { 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) { @@ -103,31 +136,43 @@ public class CityGmlZipEntry implements Serializable { this.parentArchive = parentArchive; } - public void setArchive(CityGmlZipArchive archive) { - parentArchive = archive; - } - + /** + * Gets the parent archive of this entry. + * @return the archive + */ public CityGmlZipArchive getArchive() { return parentArchive; } /** - * Gets this entry's sub-path in the archive. + * Gets the sub-path in the archive of the file associated with this entry. * - * @return Relative sub-path from the archive root directory. + * @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; } @@ -136,14 +181,20 @@ public class CityGmlZipEntry implements Serializable { 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); } /** - * Returns whether this entry has been loaded into memory. + * Checks if the {@link CityDoctorModel} of this entry has been loaded into memory. * - * @return true if + * @return true if it is loaded, false otherwise */ public boolean isLoaded() { return inMemory; @@ -152,7 +203,7 @@ public class CityGmlZipEntry implements Serializable { /** * Returns the estimated uncompressed filesize of this entry. * - * @return filesize in bytes, -1 if filesize unknown + * @return filesize in bytes, -1L if filesize is unknown */ public long getFileSize() { return fileSize; diff --git a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/zip/CityGmlZipEntryFile.java b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/zip/CityGmlZipEntryFile.java index 2d4e77b9dc08ff01f7a9aafad85c3515e30f8ea9..e8c8aaca2b74c3ad999a6327d082b46b787513b8 100644 --- a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/zip/CityGmlZipEntryFile.java +++ b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/zip/CityGmlZipEntryFile.java @@ -6,6 +6,12 @@ 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; @@ -13,6 +19,12 @@ public class CityGmlZipEntryFile implements AutoCloseable { 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()); @@ -20,6 +32,14 @@ public class CityGmlZipEntryFile implements AutoCloseable { 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("Stream closed"); @@ -27,6 +47,11 @@ public class CityGmlZipEntryFile implements AutoCloseable { 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("Stream closed"); diff --git a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/zip/ZipEntryErrorType.java b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/zip/ZipEntryErrorType.java index d68209fff07a9e7588a59549f7339c4764280c99..7dec72b42b00da211c994f85d05005916e9430bf 100644 --- a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/zip/ZipEntryErrorType.java +++ b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/zip/ZipEntryErrorType.java @@ -1,5 +1,8 @@ package de.hft.stuttgart.citydoctor2.zip; +/** + * Error types for {@link CityGmlZipEntry} objects. + */ public enum ZipEntryErrorType { INVALID_CITY_GML_FILE, EXCESSIVE_FILESIZE, IO_ERROR }