refactor(service): make validation methods non-static in VeraPDFService

- Changed `validatePDF` and `validateAllDeclaredStandards` methods from static to instance methods
- Updated comments to include explicit null checks for better NPE prevention in warning logic

Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
This commit is contained in:
Balázs Szücs 2025-11-14 21:36:21 +01:00
parent b733dae1af
commit 525864ff2c

View File

@ -61,90 +61,37 @@ public class VeraPDFService {
} }
} }
public static PDFVerificationResult validatePDF(InputStream pdfStream, String standardString) private static boolean isWarningByMessage(String message) {
throws IOException, ValidationException, ModelParsingException, EncryptedPdfException { // Check for null or blank message - explicit null check is necessary to avoid NPE
if (message == null || message.isBlank()) {
return false;
}
byte[] pdfBytes = pdfStream.readAllBytes(); String normalized = message.toLowerCase(Locale.ROOT);
PDFAFlavour validationFlavour = PDFAFlavour.fromString(standardString);
Optional<PDFAFlavour> declaredPdfaFlavour = extractDeclaredPdfaFlavour(pdfBytes);
try (PDFAParser parser = return normalized.contains("recommended")
Foundries.defaultInstance() || normalized.contains("should")
.createParser(new ByteArrayInputStream(pdfBytes), validationFlavour)) { || normalized.contains("optional")
PDFAValidator validator = || normalized.contains("missing recommended");
Foundries.defaultInstance().createValidator(validationFlavour, false); }
ValidationResult result = validator.validate(parser);
return convertToVerificationResult( private static boolean isWarningByClause(String clause) {
result, declaredPdfaFlavour.orElse(null), validationFlavour); // Check for null or blank clause - explicit null check is necessary to avoid NPE
if (clause == null || clause.isBlank()) {
return false;
}
if (clause.startsWith("6.7")) {
return true;
}
for (String criticalPrefix : CRITICAL_CLAUSE_PREFIXES) {
if (clause.startsWith(criticalPrefix)) {
return false;
} }
} }
public static List<PDFVerificationResult> validateAllDeclaredStandards(InputStream pdfStream) return true;
throws IOException, ValidationException, ModelParsingException, EncryptedPdfException {
byte[] pdfBytes = pdfStream.readAllBytes();
Optional<PDFAFlavour> declaredPdfaFlavour = extractDeclaredPdfaFlavour(pdfBytes);
List<PDFVerificationResult> results = new ArrayList<>();
List<PDFAFlavour> detectedFlavours;
try (PDFAParser detectionParser =
Foundries.defaultInstance().createParser(new ByteArrayInputStream(pdfBytes))) {
detectedFlavours = detectionParser.getFlavours();
}
List<PDFAFlavour> flavoursToValidate = new ArrayList<>();
declaredPdfaFlavour.ifPresent(flavoursToValidate::add);
for (PDFAFlavour flavour : detectedFlavours) {
if (PDFFlavours.isFlavourFamily(flavour, PDFAFlavour.SpecificationFamily.PDF_A)) {
if (declaredPdfaFlavour.isPresent() && !declaredPdfaFlavour.get().equals(flavour)) {
flavoursToValidate.add(flavour);
} else if (declaredPdfaFlavour.isEmpty()) {
log.debug(
"Ignoring detected PDF/A flavour {} because no PDF/A declaration exists in XMP",
flavour.getId());
}
} else if (PDFFlavours.isFlavourFamily(flavour, PDFAFlavour.SpecificationFamily.PDF_UA)
|| PDFFlavours.isFlavourFamily(
flavour, PDFAFlavour.SpecificationFamily.WTPDF)) {
flavoursToValidate.add(flavour);
}
}
if (declaredPdfaFlavour.isEmpty()) {
results.add(createNoPdfaDeclarationResult());
}
if (flavoursToValidate.isEmpty()) {
log.info("No verifiable PDF/A, PDF/UA, or WTPDF standards declared via XMP metadata");
return results;
}
for (PDFAFlavour flavour : flavoursToValidate) {
try (PDFAParser parser =
Foundries.defaultInstance()
.createParser(new ByteArrayInputStream(pdfBytes), flavour)) {
PDFAValidator validator =
Foundries.defaultInstance().createValidator(flavour, false);
ValidationResult result = validator.validate(parser);
PDFAFlavour declaredForResult =
PDFFlavours.isFlavourFamily(flavour, PDFAFlavour.SpecificationFamily.PDF_A)
? declaredPdfaFlavour.orElse(null)
: flavour;
results.add(convertToVerificationResult(result, declaredForResult, flavour));
} catch (Exception e) {
log.error("Error validating standard {}: {}", flavour.getId(), e.getMessage());
results.add(
buildErrorResult(
declaredPdfaFlavour,
flavour,
"Validation error: " + e.getMessage()));
}
}
return results;
} }
private static PDFVerificationResult convertToVerificationResult( private static PDFVerificationResult convertToVerificationResult(
@ -264,37 +211,90 @@ public class VeraPDFService {
return ruleId != null && WARNING_RULES.contains(ruleId); return ruleId != null && WARNING_RULES.contains(ruleId);
} }
private static boolean isWarningByMessage(String message) { public PDFVerificationResult validatePDF(InputStream pdfStream, String standardString)
// isBlank() already handles null and empty strings throws IOException, ValidationException, ModelParsingException, EncryptedPdfException {
if (message == null || message.isBlank()) {
return false;
}
String normalized = message.toLowerCase(Locale.ROOT); byte[] pdfBytes = pdfStream.readAllBytes();
PDFAFlavour validationFlavour = PDFAFlavour.fromString(standardString);
Optional<PDFAFlavour> declaredPdfaFlavour = extractDeclaredPdfaFlavour(pdfBytes);
return normalized.contains("recommended") try (PDFAParser parser =
|| normalized.contains("should") Foundries.defaultInstance()
|| normalized.contains("optional") .createParser(new ByteArrayInputStream(pdfBytes), validationFlavour)) {
|| normalized.contains("missing recommended"); PDFAValidator validator =
} Foundries.defaultInstance().createValidator(validationFlavour, false);
ValidationResult result = validator.validate(parser);
private static boolean isWarningByClause(String clause) { return convertToVerificationResult(
// isBlank() already handles null and empty strings result, declaredPdfaFlavour.orElse(null), validationFlavour);
if (clause == null || clause.isBlank()) {
return false;
}
if (clause.startsWith("6.7")) {
return true;
}
for (String criticalPrefix : CRITICAL_CLAUSE_PREFIXES) {
if (clause.startsWith(criticalPrefix)) {
return false;
} }
} }
return true; public List<PDFVerificationResult> validateAllDeclaredStandards(InputStream pdfStream)
throws IOException, ValidationException, ModelParsingException, EncryptedPdfException {
byte[] pdfBytes = pdfStream.readAllBytes();
Optional<PDFAFlavour> declaredPdfaFlavour = extractDeclaredPdfaFlavour(pdfBytes);
List<PDFVerificationResult> results = new ArrayList<>();
List<PDFAFlavour> detectedFlavours;
try (PDFAParser detectionParser =
Foundries.defaultInstance().createParser(new ByteArrayInputStream(pdfBytes))) {
detectedFlavours = detectionParser.getFlavours();
}
List<PDFAFlavour> flavoursToValidate = new ArrayList<>();
declaredPdfaFlavour.ifPresent(flavoursToValidate::add);
for (PDFAFlavour flavour : detectedFlavours) {
if (PDFFlavours.isFlavourFamily(flavour, PDFAFlavour.SpecificationFamily.PDF_A)) {
if (declaredPdfaFlavour.isPresent() && !declaredPdfaFlavour.get().equals(flavour)) {
flavoursToValidate.add(flavour);
} else if (declaredPdfaFlavour.isEmpty()) {
log.debug(
"Ignoring detected PDF/A flavour {} because no PDF/A declaration exists in XMP",
flavour.getId());
}
} else if (PDFFlavours.isFlavourFamily(flavour, PDFAFlavour.SpecificationFamily.PDF_UA)
|| PDFFlavours.isFlavourFamily(
flavour, PDFAFlavour.SpecificationFamily.WTPDF)) {
flavoursToValidate.add(flavour);
}
}
if (declaredPdfaFlavour.isEmpty()) {
results.add(createNoPdfaDeclarationResult());
}
if (flavoursToValidate.isEmpty()) {
log.info("No verifiable PDF/A, PDF/UA, or WTPDF standards declared via XMP metadata");
return results;
}
for (PDFAFlavour flavour : flavoursToValidate) {
try (PDFAParser parser =
Foundries.defaultInstance()
.createParser(new ByteArrayInputStream(pdfBytes), flavour)) {
PDFAValidator validator =
Foundries.defaultInstance().createValidator(flavour, false);
ValidationResult result = validator.validate(parser);
PDFAFlavour declaredForResult =
PDFFlavours.isFlavourFamily(flavour, PDFAFlavour.SpecificationFamily.PDF_A)
? declaredPdfaFlavour.orElse(null)
: flavour;
results.add(convertToVerificationResult(result, declaredForResult, flavour));
} catch (Exception e) {
log.error("Error validating standard {}: {}", flavour.getId(), e.getMessage());
results.add(
buildErrorResult(
declaredPdfaFlavour,
flavour,
"Validation error: " + e.getMessage()));
}
}
return results;
} }
private static PDFVerificationResult createNoPdfaDeclarationResult() { private static PDFVerificationResult createNoPdfaDeclarationResult() {