/*
*
* Copyright (c) 2013 - 2017 Lijun Liao
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License version 3
* as published by the Free Software Foundation with the addition of the
* following permission added to Section 15 as permitted in Section 7(a):
*
* FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
* THE AUTHOR LIJUN LIAO. LIJUN LIAO DISCLAIMS THE WARRANTY OF NON INFRINGEMENT
* OF THIRD PARTY RIGHTS.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License.
*
* You can be released from the requirements of the license by purchasing
* a commercial license. Buying such a license is mandatory as soon as you
* develop commercial activities involving the XiPKI software without
* disclosing the source code of your own applications.
*
* For more information, please contact Lijun Liao at this
* address: lijun.liao@gmail.com
*/
package org.xipki.pki.ca.dbtool.diffdb;
import java.io.IOException;
import java.math.BigInteger;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xipki.commons.common.EndOfQueue;
import org.xipki.commons.common.QueueEntry;
import org.xipki.commons.common.util.ParamUtil;
import org.xipki.commons.datasource.DataSourceWrapper;
import org.xipki.commons.datasource.springframework.dao.DataAccessException;
import org.xipki.commons.security.util.X509Util;
import org.xipki.pki.ca.dbtool.DbToolBase;
import org.xipki.pki.ca.dbtool.StopMe;
import org.xipki.pki.ca.dbtool.diffdb.io.CertsBundle;
import org.xipki.pki.ca.dbtool.diffdb.io.DbDigestEntry;
import org.xipki.pki.ca.dbtool.diffdb.io.DigestDbEntrySet;
import org.xipki.pki.ca.dbtool.diffdb.io.IdentifiedDbDigestEntry;
/**
* @author Lijun Liao
* @since 2.0.0
*/
abstract class DbDigestReader implements DigestReader {
private static final Logger LOG = LoggerFactory.getLogger(DbDigestReader.class);
protected final BlockingQueue<QueueEntry> outQueue;
protected final DataSourceWrapper datasource;
protected final X509Certificate caCert;
protected final StopMe stopMe;
private ExecutorService executor;
private Retriever retriever;
private final int totalAccount;
private final String caSubjectName;
private final AtomicBoolean endReached = new AtomicBoolean(false);
protected long lastProcessedId;
DbDigestReader(final DataSourceWrapper datasource, final X509Certificate caCert,
final int totalAccount, final long minId, final int numBlocksToRead,
final StopMe stopMe) throws DataAccessException, CertificateException, IOException {
this.datasource = ParamUtil.requireNonNull("datasource", datasource);
this.caCert = ParamUtil.requireNonNull("caCert", caCert);
this.stopMe = ParamUtil.requireNonNull("stopMe", stopMe);
this.totalAccount = totalAccount;
this.caSubjectName = X509Util.getRfc4519Name(caCert.getSubjectX500Principal());
this.lastProcessedId = minId - 1;
this.outQueue = new ArrayBlockingQueue<>(numBlocksToRead);
}
interface Retriever extends Runnable {
} // interface Retriever
boolean init() {
try {
retriever = getRetriever();
executor = Executors.newFixedThreadPool(1);
executor.execute(retriever);
return true;
} catch (Exception ex) {
LOG.error("could not initialize DbDigestReader", ex);
close();
return false;
}
}
protected abstract Retriever getRetriever() throws DataAccessException;
@Override
public X509Certificate getCaCert() {
return caCert;
}
@Override
public String getCaSubjectName() {
return caSubjectName;
}
@Override
public int getTotalAccount() {
return totalAccount;
}
@Override
public synchronized CertsBundle nextCerts() throws Exception {
if (endReached.get() && outQueue.isEmpty()) {
return null;
}
DigestDbEntrySet certSet;
QueueEntry next = null;
while (next == null) {
if (stopMe.stopMe()) {
return null;
}
next = outQueue.poll(1, TimeUnit.SECONDS);
}
if (next instanceof EndOfQueue) {
endReached.set(true);
return null;
} else if (!(next instanceof DigestDbEntrySet)) {
throw new RuntimeException("unknown QueueEntry type: " + next.getClass().getName());
}
certSet = (DigestDbEntrySet) next;
if (certSet.getException() != null) {
throw certSet.getException();
}
List<BigInteger> serialNumbers = new LinkedList<>();
Map<BigInteger, DbDigestEntry> certsMap = new HashMap<>();
for (IdentifiedDbDigestEntry m : certSet.getEntries()) {
BigInteger sn = m.getContent().getSerialNumber();
serialNumbers.add(sn);
certsMap.put(sn, m.getContent());
}
return new CertsBundle(certsMap, serialNumbers);
} // method nextCerts
public void close() {
if (executor != null) {
executor.shutdownNow();
}
}
protected void releaseResources(final Statement ps, final ResultSet rs) {
DbToolBase.releaseResources(datasource, ps, rs);
}
}