/** Load the certificates contained in all the TSL referenced by the LOTL */
  public void init() {

    diagnosticInfo.clear();

    X509Certificate lotlCert = null;
    if (checkSignature) {

      lotlCert = readLOTLCertificate();
    }
    TrustStatusList lotl;
    try {

      LOG.info("Downloading LOTL from url= {}", lotlUrl);
      final ArrayList<X509Certificate> x509CertificateList = new ArrayList<X509Certificate>();
      x509CertificateList.add(lotlCert);
      lotl = getTrustStatusList(lotlUrl, x509CertificateList);
    } catch (DSSException e) {

      LOG.error("The LOTL cannot be loaded: " + e.getMessage(), e);
      throw e;
    }
    diagnosticInfo.put(lotlUrl, "Loaded " + new Date().toString());
    final int size = lotl.getOtherTSLPointers().size();
    //        final ExecutorService executorService = Executors.newFixedThreadPool(size);
    //        List<Future> futures = new ArrayList<Future>(size);
    for (final PointerToOtherTSL pointerToTSL : lotl.getOtherTSLPointers()) {
      //            Runnable runnable = new Runnable() {
      //                public void run() {

      final String url = pointerToTSL.getTslLocation();
      final String territory = pointerToTSL.getTerritory();
      final List<X509Certificate> signingCertList = pointerToTSL.getDigitalIdentity();
      try {

        loadTSL(url, territory, signingCertList);
      } catch (DSSException e) {
        LOG.error("Error loading trusted list for {} at {}", new Object[] {territory, url, e});
        // do nothing continue with the next trusted list.
      }

      //                }
      //            };
      //            final Future submit = executorService.submit(runnable);
      //            futures.add(submit);
    }

    //        executorService.shutdown();
    //        while (!executorService.isTerminated()){
    //            try {
    //                Thread.sleep(100);
    //            } catch (InterruptedException e) {
    //                throw new RuntimeException(e);
    //            }
    //        }
    //        LOG.info("Parallel download of Trusted list done");
    loadAdditionalLists();
    LOG.info("Loading completed: {} trusted lists", size);
    LOG.info("                 : {} certificates", certPool.getNumberOfCertificates());
  }
  /**
   * Load a trusted list for the specified URL
   *
   * @param url
   * @param signingCertList
   * @return
   * @throws java.io.IOException
   */
  private TrustStatusList getTrustStatusList(
      final String url, final List<X509Certificate> signingCertList) {

    byte[] bytes = dataLoader.get(url);
    if (bytes == null) {

      throw new DSSNullReturnedException(url);
    }
    final Document doc = DSSXMLUtils.buildDOM(bytes);

    boolean coreValidity = true;
    if (checkSignature) {

      coreValidity = false;
      if (signingCertList != null) {

        final CommonTrustedCertificateSource commonTrustedCertificateSource =
            new CommonTrustedCertificateSource();
        for (final X509Certificate x509Certificate : signingCertList) {

          commonTrustedCertificateSource.addCertificate(x509Certificate);
        }
        final CertificateVerifier certificateVerifier = new CommonCertificateVerifier(true);
        certificateVerifier.setTrustedCertSource(commonTrustedCertificateSource);

        final DSSDocument dssDocument = new InMemoryDocument(bytes);
        final XMLDocumentValidator xmlDocumentValidator = new XMLDocumentValidator(dssDocument);
        xmlDocumentValidator.setCertificateVerifier(certificateVerifier);
        // To increase the security: the default {@code XPathQueryHolder} is used.
        final List<XPathQueryHolder> xPathQueryHolders = xmlDocumentValidator.getXPathQueryHolder();
        xPathQueryHolders.clear();
        final XPathQueryHolder xPathQueryHolder = new XPathQueryHolder();
        xPathQueryHolders.add(xPathQueryHolder);

        final List<AdvancedSignature> signatures = xmlDocumentValidator.getSignatures();
        if (signatures.size() == 0) {

          throw new DSSException("Not ETSI compliant signature. The Xml is not signed.");
        }

        xmlDocumentValidator.validateDocument();
        final SimpleReport simpleReport = xmlDocumentValidator.getSimpleReport();
        final List<String> signatureIdList = simpleReport.getSignatureIds();
        final String signatureId = signatureIdList.get(0);
        final String indication = simpleReport.getIndication(signatureId);
        coreValidity = Indication.VALID.equals(indication);
        LOG.info("The TSL signature validity: " + coreValidity);
        if (!coreValidity) {

          LOG.info("The TSL signature validity details:\n" + simpleReport);
          System.out.println(xmlDocumentValidator.getDiagnosticData());
          throw new DSSException("Not ETSI compliant signature. The signature is not valid.");
        }
      }
    }
    final TrustStatusList tsl = TrustServiceListFactory.newInstance(doc);
    tsl.setWellSigned(coreValidity);
    return tsl;
  }
  /**
   * Adds all the service entries (current and history) of all the providers of the trusted list to
   * the list of CertificateSource
   *
   * @param trustStatusList
   */
  private void loadAllCertificatesFromOneTSL(final TrustStatusList trustStatusList) {

    for (final TrustServiceProvider trustServiceProvider :
        trustStatusList.getTrustServicesProvider()) {

      for (final AbstractTrustService trustService : trustServiceProvider.getTrustServiceList()) {

        if (LOG.isTraceEnabled()) {
          LOG.trace("### " + trustService.getServiceName());
          LOG.trace("------> " + trustService.getType());
          LOG.trace("------> " + trustService.getStatus());
        }

        for (final Object digitalIdentity : trustService.getDigitalIdentity()) {

          try {

            X509Certificate x509Certificate = null;
            if (digitalIdentity instanceof X509Certificate) {

              x509Certificate = (X509Certificate) digitalIdentity;
            } else if (digitalIdentity instanceof X500Principal) {

              final X500Principal x500Principal = (X500Principal) digitalIdentity;
              final List<CertificateToken> certificateTokens = certPool.get(x500Principal);
              if (certificateTokens.size() > 0) {
                x509Certificate = certificateTokens.get(0).getCertificate();
              } else {
                LOG.warn(
                    "There is currently no certificate with the given X500Principal: '{}' within the certificate pool!",
                    x500Principal);
              }
            }
            if (x509Certificate != null) {

              addCertificate(
                  x509Certificate,
                  trustService,
                  trustServiceProvider,
                  trustStatusList.isWellSigned());
            }
          } catch (DSSException e) {

            // There is a problem when loading the certificate, we continue with the next one.
            LOG.warn(e.getLocalizedMessage());
          }
        }
      }
    }
  }