/* DigiDoc4J library * * This software is released under either the GNU Library General Public * License (see LICENSE.LGPL). * * Note that the only valid version of the LGPL license as far as this * project is concerned is the original GNU Library General Public License * Version 2.1, February 1999 */ package org.digidoc4j.impl.bdoc.asic; import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import org.digidoc4j.Configuration; import org.digidoc4j.Signature; import org.digidoc4j.SignatureValidationResult; import org.digidoc4j.ValidationResult; import org.digidoc4j.exceptions.DigiDoc4JException; import org.digidoc4j.exceptions.TechnicalException; import org.digidoc4j.exceptions.UnsupportedFormatException; import org.digidoc4j.impl.bdoc.BDocValidationReportBuilder; import org.digidoc4j.impl.bdoc.BDocValidationResult; import org.digidoc4j.impl.bdoc.manifest.ManifestParser; import org.digidoc4j.impl.bdoc.manifest.ManifestValidator; import org.digidoc4j.impl.bdoc.xades.validation.SignatureValidationData; import org.digidoc4j.impl.bdoc.xades.validation.SignatureValidationTask; import org.digidoc4j.impl.bdoc.xades.validation.ThreadPoolManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import eu.europa.esig.dss.DSSDocument; public class BDocContainerValidator implements Serializable { private final static Logger logger = LoggerFactory.getLogger(BDocContainerValidator.class); private List<DigiDoc4JException> errors = new ArrayList<>(); private List<DigiDoc4JException> warnings = new ArrayList<>(); private AsicParseResult containerParseResult; private boolean validateManifest; private List<SignatureValidationData> signatureValidationData = new ArrayList<>(); private List<DigiDoc4JException> manifestErrors; private ThreadPoolManager threadPoolManager; public BDocContainerValidator(Configuration configuration) { threadPoolManager = new ThreadPoolManager(configuration); validateManifest = false; } public BDocContainerValidator(AsicParseResult containerParseResult, Configuration configuration) { this.containerParseResult = containerParseResult; threadPoolManager = new ThreadPoolManager(configuration); validateManifest = true; } public ValidationResult validate(List<Signature> signatures) { logger.debug("Validating container"); validateSignatures(signatures); extractManifestErrors(signatures); BDocValidationResult result = createValidationResult(); logger.info("Is container valid: " + result.isValid()); return result; } private void validateSignatures(List<Signature> signatures) { List<Future<SignatureValidationData>> validationData = startSignatureValidationInParallel(signatures); extractValidatedSignatureErrors(validationData); } private List<Future<SignatureValidationData>> startSignatureValidationInParallel(List<Signature> signatures) { List<Future<SignatureValidationData>> futures = new ArrayList<>(); for (Signature signature : signatures) { SignatureValidationTask validationExecutor = new SignatureValidationTask(signature); Future<SignatureValidationData> validationDataFuture = threadPoolManager.submit(validationExecutor); futures.add(validationDataFuture); } return futures; } private void extractValidatedSignatureErrors(List<Future<SignatureValidationData>> validationFutures) { logger.debug("Extracting errors from the signatures"); for (Future<SignatureValidationData> validationFuture : validationFutures) { try { SignatureValidationData validationData = validationFuture.get(); extractSignatureErrors(validationData); } catch (InterruptedException | ExecutionException e) { logger.error("Error validating signatures on multiple threads: " + e.getMessage()); throw new TechnicalException("Error validating signatures on multiple threads: " + e.getMessage(), e); } } } public void setValidateManifest(boolean validateManifest) { this.validateManifest = validateManifest; } private void extractSignatureErrors(SignatureValidationData validationData) { logger.debug("Extracting signature errors for signature " + validationData.getSignatureId()); signatureValidationData.add(validationData); SignatureValidationResult validationResult = validationData.getValidationResult(); List<DigiDoc4JException> signatureErrors = validationResult.getErrors(); errors.addAll(signatureErrors); warnings.addAll(validationResult.getWarnings()); } private void extractManifestErrors(List<Signature> signatures) { logger.debug("Extracting manifest errors"); manifestErrors = findManifestErrors(signatures); errors.addAll(manifestErrors); } private BDocValidationResult createValidationResult() { BDocValidationReportBuilder reportBuilder = new BDocValidationReportBuilder(signatureValidationData, manifestErrors); BDocValidationResult result = new BDocValidationResult(); result.setErrors(errors); result.setWarnings(warnings); result.setContainerErrorsOnly(manifestErrors); result.setReportBuilder(reportBuilder); return result; } private List<DigiDoc4JException> findManifestErrors(List<Signature> signatures) { if (!validateManifest || containerParseResult == null) { return Collections.emptyList(); } ManifestParser manifestParser = containerParseResult.getManifestParser(); if (manifestParser == null || !manifestParser.containsManifestFile()) { logger.error("Container is missing manifest.xml"); List<DigiDoc4JException> manifestExceptions = new ArrayList<>(); manifestExceptions.add(new UnsupportedFormatException("Container does not contain a manifest file")); return manifestExceptions; } List<DigiDoc4JException> manifestExceptions = new ArrayList<>(); List<DSSDocument> detachedContents = containerParseResult.getDetachedContents(); List<String> manifestErrors = new ManifestValidator(manifestParser, detachedContents, signatures).validateDocument(); for (String manifestError : manifestErrors) { manifestExceptions.add(new DigiDoc4JException(manifestError)); } return manifestExceptions; } }