/* 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.tsl; import java.security.cert.X509Certificate; import java.util.Date; import java.util.List; import javax.security.auth.x500.X500Principal; import org.digidoc4j.TSLCertificateSource; import org.digidoc4j.exceptions.TslCertificateSourceInitializationException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import eu.europa.esig.dss.DSSException; import eu.europa.esig.dss.tsl.ServiceInfo; import eu.europa.esig.dss.tsl.service.TSLValidationJob; import eu.europa.esig.dss.x509.CertificatePool; import eu.europa.esig.dss.x509.CertificateToken; /** * Lazily initialized certificate source. It allows to initialize objects and populate parameters * where a certificate source is necessary, but is not yet accessed. * * The goal is to postpone initialization and downloading of TSL until it is really needed to speed up processes. * For example, it is not necessary to download TSL to open container and see signature parameters, but DSS library * requires the presence of certificate source. TSL should be downloaded for validation and other functionality where * it is really necessary to check the certificates. * * To achieve that, a lazily initialized certificate source is used. */ public class LazyTslCertificateSource implements TSLCertificateSource { private static final Logger logger = LoggerFactory.getLogger(LazyTslCertificateSource.class); private TSLCertificateSource certificateSource; private transient TSLValidationJob tslValidationJob; private Long lastCacheReloadingTime; private Long cacheExpirationTime; private TslLoader tslLoader; public LazyTslCertificateSource(TslLoader tslLoader) { logger.debug("Initializing lazy TSL certificate source"); this.tslLoader = tslLoader; } @Override public CertificatePool getCertificatePool() { return getCertificateSource().getCertificatePool(); } @Override public CertificateToken addCertificate(CertificateToken certificate) { return getCertificateSource().addCertificate(certificate); } @Override public List<CertificateToken> get(X500Principal x500Principal) { return getCertificateSource().get(x500Principal); } @Override public void addTSLCertificate(X509Certificate certificate) { getCertificateSource().addTSLCertificate(certificate); } @Override public CertificateToken addCertificate(CertificateToken certificate, ServiceInfo serviceInfo) { return getCertificateSource().addCertificate(certificate, serviceInfo); } @Override public List<CertificateToken> getCertificates() { return getCertificateSource().getCertificates(); } @Override public void invalidateCache() { logger.debug("Invalidating TSL cache"); TslLoader.invalidateCache(); } @Override public void refresh() { refreshTsl(); } public void setCacheExpirationTime(Long cacheExpirationTime) { this.cacheExpirationTime = cacheExpirationTime; } protected void refreshIfCacheExpired() { if(isCacheExpired()) { initTsl(); } } Long getCacheExpirationTime() { return cacheExpirationTime; } Long getLastCacheReloadingTime() { return lastCacheReloadingTime; } private TSLCertificateSource getCertificateSource() { logger.debug("Accessing TSL"); refreshIfCacheExpired(); return certificateSource; } private synchronized void initTsl() { //Using double-checked locking to avoid other threads to start loading TSL if(isCacheExpired()) { logger.debug("Initializing TSL"); refreshTsl(); } } private synchronized void refreshTsl() { try { populateTsl(); logger.debug("Refreshing TSL"); tslValidationJob.refresh(); lastCacheReloadingTime = new Date().getTime(); if(logger.isDebugEnabled()) { logger.debug("Finished refreshing TSL, cache expires at " + getNextCacheExpirationDate()); } } catch (DSSException e) { logger.error("Unable to load TSL: " + e.getMessage()); throw new TslCertificateSourceInitializationException(e.getMessage()); } } private void populateTsl() { if(tslValidationJob == null || certificateSource == null) { tslLoader.prepareTsl(); tslValidationJob = tslLoader.getTslValidationJob(); certificateSource = tslLoader.getTslCertificateSource(); } } private boolean isCacheExpired() { if(lastCacheReloadingTime == null) { return true; } long currentTime = new Date().getTime(); long timeToReload = lastCacheReloadingTime + cacheExpirationTime; return currentTime > timeToReload; } private String getNextCacheExpirationDate() { return new Date(lastCacheReloadingTime + cacheExpirationTime).toString(); } }