278 lines
9.6 KiB
Java
278 lines
9.6 KiB
Java
package org.nd4j.validation;
|
|
|
|
import lombok.NonNull;
|
|
import org.apache.commons.io.FileUtils;
|
|
import org.nd4j.shade.jackson.databind.JavaType;
|
|
import org.nd4j.shade.jackson.databind.ObjectMapper;
|
|
|
|
import java.io.File;
|
|
import java.io.IOException;
|
|
import java.nio.charset.Charset;
|
|
import java.nio.charset.StandardCharsets;
|
|
import java.util.*;
|
|
import java.util.zip.ZipEntry;
|
|
import java.util.zip.ZipFile;
|
|
|
|
/**
|
|
* A utility for validating multiple file formats that ND4J and other tools can read
|
|
*
|
|
* @author Alex Black
|
|
*/
|
|
public class Nd4jCommonValidator {
|
|
|
|
private Nd4jCommonValidator() {
|
|
}
|
|
|
|
/**
|
|
* Validate whether the specified file is a valid file (must exist and be non-empty)
|
|
*
|
|
* @param f File to check
|
|
* @return Result of validation
|
|
*/
|
|
public static ValidationResult isValidFile(@NonNull File f) {
|
|
ValidationResult vr = isValidFile(f, "File", false);
|
|
if (vr != null)
|
|
return vr;
|
|
return ValidationResult.builder()
|
|
.valid(true)
|
|
.formatType("File")
|
|
.path(getPath(f))
|
|
.build();
|
|
}
|
|
|
|
/**
|
|
* Validate whether the specified file is a valid file
|
|
*
|
|
* @param f File to check
|
|
* @param formatType Name of the file format to include in validation results
|
|
* @param allowEmpty If true: allow empty files to pass. False: empty files will fail validation
|
|
* @return Result of validation
|
|
*/
|
|
public static ValidationResult isValidFile(@NonNull File f, String formatType, boolean allowEmpty) {
|
|
String path;
|
|
try {
|
|
path = f.getAbsolutePath(); //Very occasionally: getAbsolutePath not possible (files in JARs etc)
|
|
} catch (Throwable t) {
|
|
path = f.getPath();
|
|
}
|
|
|
|
if (f.exists() && !f.isFile()) {
|
|
return ValidationResult.builder()
|
|
.valid(false)
|
|
.formatType(formatType)
|
|
.path(path)
|
|
.issues(Collections.singletonList(f.isDirectory() ? "Specified path is a directory" : "Specified path is not a file"))
|
|
.build();
|
|
}
|
|
|
|
if (!f.exists() || !f.isFile()) {
|
|
return ValidationResult.builder()
|
|
.valid(false)
|
|
.formatType(formatType)
|
|
.path(path)
|
|
.issues(Collections.singletonList("File does not exist"))
|
|
.build();
|
|
}
|
|
|
|
if (!allowEmpty && f.length() <= 0) {
|
|
return ValidationResult.builder()
|
|
.valid(false)
|
|
.formatType(formatType)
|
|
.path(path)
|
|
.issues(Collections.singletonList("File is empty (length 0)"))
|
|
.build();
|
|
}
|
|
|
|
return null; //OK
|
|
}
|
|
|
|
public static ValidationResult isValidJsonUTF8(@NonNull File f) {
|
|
return isValidJson(f, StandardCharsets.UTF_8);
|
|
}
|
|
|
|
/**
|
|
* Validate whether the specified file is a valid JSON file. Note that this does not match the JSON content against a specific schema
|
|
*
|
|
* @param f File to check
|
|
* @param charset Character set for file
|
|
* @return Result of validation
|
|
*/
|
|
public static ValidationResult isValidJson(@NonNull File f, Charset charset) {
|
|
|
|
ValidationResult vr = isValidFile(f, "JSON", false);
|
|
if (vr != null)
|
|
return vr;
|
|
|
|
String content;
|
|
try {
|
|
content = FileUtils.readFileToString(f, charset);
|
|
} catch (IOException e) {
|
|
return ValidationResult.builder()
|
|
.valid(false)
|
|
.formatType("JSON")
|
|
.path(getPath(f))
|
|
.issues(Collections.singletonList("Unable to read file (IOException)"))
|
|
.exception(e)
|
|
.build();
|
|
}
|
|
|
|
|
|
return isValidJson(content, f);
|
|
}
|
|
|
|
/**
|
|
* Validate whether the specified String is valid JSON. Note that this does not match the JSON content against a specific schema
|
|
*
|
|
* @param s JSON String to check
|
|
* @return Result of validation
|
|
*/
|
|
public static ValidationResult isValidJSON(String s) {
|
|
return isValidJson(s, null);
|
|
}
|
|
|
|
|
|
protected static ValidationResult isValidJson(String content, File f) {
|
|
try {
|
|
ObjectMapper om = new ObjectMapper();
|
|
JavaType javaType = om.getTypeFactory().constructMapType(Map.class, String.class, Object.class);
|
|
om.readValue(content, javaType); //Don't care about result, just that it can be parsed successfully
|
|
} catch (Throwable t) {
|
|
//Jackson should tell us specifically where error occurred also
|
|
return ValidationResult.builder()
|
|
.valid(false)
|
|
.formatType("JSON")
|
|
.path(getPath(f))
|
|
.issues(Collections.singletonList("File does not appear to be valid JSON"))
|
|
.exception(t)
|
|
.build();
|
|
}
|
|
|
|
|
|
return ValidationResult.builder()
|
|
.valid(true)
|
|
.formatType("JSON")
|
|
.path(getPath(f))
|
|
.build();
|
|
}
|
|
|
|
|
|
/**
|
|
* Validate whether the specified file is a valid Zip file
|
|
*
|
|
* @param f File to check
|
|
* @param allowEmpty If true: allow empty zip files to pass validation. False: empty zip files will fail validation.
|
|
* @return Result of validation
|
|
*/
|
|
public static ValidationResult isValidZipFile(@NonNull File f, boolean allowEmpty) {
|
|
return isValidZipFile(f, allowEmpty, (List<String>) null);
|
|
}
|
|
|
|
/**
|
|
* Validate whether the specified file is a valid Zip file
|
|
*
|
|
* @param f File to check
|
|
* @param allowEmpty If true: allow empty zip files to pass validation. False: empty zip files will fail validation.
|
|
* @return Result of validation
|
|
*/
|
|
public static ValidationResult isValidZipFile(@NonNull File f, boolean allowEmpty, String... requiredEntries) {
|
|
return isValidZipFile(f, allowEmpty, requiredEntries == null ? null : Arrays.asList(requiredEntries));
|
|
}
|
|
|
|
/**
|
|
* Validate whether the specified file is a valid Zip file, and contains all of the required entries
|
|
*
|
|
* @param f File to check
|
|
* @param allowEmpty If true: allow empty zip files to pass validation. False: empty zip files will fail validation.
|
|
* @param requiredEntries If non-null, all of the specified entries must be present for the file to pass validation
|
|
* @return Result of validation
|
|
*/
|
|
public static ValidationResult isValidZipFile(@NonNull File f, boolean allowEmpty, List<String> requiredEntries) {
|
|
ValidationResult vr = isValidFile(f, "Zip File", false);
|
|
if (vr != null)
|
|
return vr;
|
|
|
|
ZipFile zf;
|
|
try {
|
|
zf = new ZipFile(f);
|
|
} catch (Throwable e) {
|
|
return ValidationResult.builder()
|
|
.valid(false)
|
|
.formatType("Zip File")
|
|
.path(getPath(f))
|
|
.issues(Collections.singletonList("File does not appear to be valid zip file (not a zip file or content is corrupt)"))
|
|
.exception(e)
|
|
.build();
|
|
}
|
|
|
|
try {
|
|
int numEntries = zf.size();
|
|
if (!allowEmpty && numEntries <= 0) {
|
|
return ValidationResult.builder()
|
|
.valid(false)
|
|
.formatType("Zip File")
|
|
.path(getPath(f))
|
|
.issues(Collections.singletonList("Zip file is empty"))
|
|
.build();
|
|
}
|
|
|
|
if (requiredEntries != null && !requiredEntries.isEmpty()) {
|
|
List<String> missing = null;
|
|
for (String s : requiredEntries) {
|
|
ZipEntry ze = zf.getEntry(s);
|
|
if (ze == null) {
|
|
if (missing == null)
|
|
missing = new ArrayList<>();
|
|
missing.add(s);
|
|
}
|
|
}
|
|
|
|
if (missing != null) {
|
|
String s = "Zip file is missing " + missing.size() + " of " + requiredEntries.size() + " required entries: " + missing;
|
|
return ValidationResult.builder()
|
|
.valid(false)
|
|
.formatType("Zip File")
|
|
.path(getPath(f))
|
|
.issues(Collections.singletonList(s))
|
|
.build();
|
|
}
|
|
}
|
|
|
|
} catch (Throwable t) {
|
|
return ValidationResult.builder()
|
|
.valid(false)
|
|
.formatType("Zip File")
|
|
.path(getPath(f))
|
|
.issues(Collections.singletonList("Error reading zip file"))
|
|
.exception(t)
|
|
.build();
|
|
} finally {
|
|
try {
|
|
zf.close();
|
|
} catch (IOException e) {
|
|
} //Ignore, can't do anything about it...
|
|
}
|
|
|
|
return ValidationResult.builder()
|
|
.valid(true)
|
|
.formatType("Zip File")
|
|
.path(getPath(f))
|
|
.build();
|
|
}
|
|
|
|
|
|
/**
|
|
* Null-safe and "no absolute path exists" safe method for getting the path of a file for validation purposes
|
|
*/
|
|
public static String getPath(File f) {
|
|
if (f == null)
|
|
return null;
|
|
try {
|
|
return f.getAbsolutePath(); //Very occasionally: getAbsolutePath not possible (files in JARs etc)
|
|
} catch (Throwable t) {
|
|
return f.getPath();
|
|
}
|
|
}
|
|
|
|
|
|
}
|