All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.xipki.ca.server.impl.CertRepublisher Maven / Gradle / Ivy

/*
 *
 * Copyright (c) 2013 - 2017 Lijun Liao
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.xipki.ca.server.impl;

import java.security.cert.CertificateException;
import java.util.ArrayList;
import java.util.List;
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.ca.api.NameId;
import org.xipki.ca.api.OperationException;
import org.xipki.ca.api.publisher.x509.X509CertificateInfo;
import org.xipki.ca.server.impl.store.CertificateStore;
import org.xipki.common.EndOfQueue;
import org.xipki.common.ProcessLog;
import org.xipki.common.QueueEntry;
import org.xipki.common.util.LogUtil;
import org.xipki.common.util.ParamUtil;
import org.xipki.security.X509Cert;

/**
 * @author Lijun Liao
 * @since 2.1.0
 */

class CertRepublisher {

    private class SerialWithIdQueueEntry implements QueueEntry {

        private final SerialWithId serialWithId;

        public SerialWithIdQueueEntry(final SerialWithId serialWithId) {
            this.serialWithId = ParamUtil.requireNonNull("serialWithId", serialWithId);
        }

        public SerialWithId serialWithId() {
            return serialWithId;
        }

    }

    private class CertRepublishProducer implements Runnable {

        private boolean failed;

        private CertRepublishProducer() {
        }

        @Override
        public void run() {
            final int numEntries = 100;
            long startId = 1;

            try {
                List serials;
                do {
                    serials = certstore.getCertSerials(ca, startId, numEntries,
                            onlyRevokedCerts);
                    long maxId = 1;
                    for (SerialWithId sid : serials) {
                        if (sid.id() > maxId) {
                            maxId = sid.id();
                        }
                        queue.put(new SerialWithIdQueueEntry(sid));
                    }

                    startId = maxId + 1;
                }
                while (serials.size() >= numEntries && !failed && !stopMe.get());

                queue.put(EndOfQueue.INSTANCE);
            } catch (OperationException ex) {
                LogUtil.error(LOG, ex, "error in RepublishProducer");
                failed = true;
            } catch (InterruptedException ex) {
                LogUtil.error(LOG, ex, "error in RepublishProducer");
                failed = true;
            }

            if (!queue.contains(EndOfQueue.INSTANCE)) {
                try {
                    queue.put(EndOfQueue.INSTANCE);
                } catch (InterruptedException ex) {
                    LogUtil.error(LOG, ex, "error in RepublishProducer");
                    failed = true;
                }
            }
        }
    }

    private class CertRepublishConsumer implements Runnable {

        private boolean failed;

        private CertRepublishConsumer() {
        }

        @Override
        public void run() {
            while (!failed) {
                QueueEntry entry;
                try {
                    entry = queue.take();
                } catch (InterruptedException ex) {
                    LogUtil.error(LOG, ex, "could not take from queue");
                    failed = true;
                    break;
                }

                if (entry instanceof EndOfQueue) {
                    // re-add it to queue so that other consumers know it
                    try {
                        queue.put(entry);
                    } catch (InterruptedException ex) {
                        LogUtil.warn(LOG, ex, "could not re-add EndOfQueue to queue");
                    }
                    break;
                }

                SerialWithId sid = ((SerialWithIdQueueEntry) entry).serialWithId();

                X509CertificateInfo certInfo;

                try {
                    certInfo = certstore.getCertificateInfoForId(ca, caCert, sid.id(),
                            caIdNameMap);
                } catch (OperationException | CertificateException ex) {
                    LogUtil.error(LOG, ex);
                    failed = true;
                    break;
                }

                boolean allSucc = true;
                for (IdentifiedX509CertPublisher publisher : publishers) {
                    if (!certInfo.isRevoked() && !publisher.publishsGoodCert()) {
                        continue;
                    }

                    boolean successful = publisher.certificateAdded(certInfo);
                    if (!successful) {
                        LOG.error("republish certificate serial={} to publisher {} failed",
                                LogUtil.formatCsn(sid.serial()), publisher.ident());
                        allSucc = false;
                    }
                }

                if (!allSucc) {
                    break;
                }
                processLog.addNumProcessed(1);
            }
        }

    }

    private static final Logger LOG = LoggerFactory.getLogger(CertRepublisher.class);

    private final NameId ca;

    private final X509Cert caCert;

    private final CaIdNameMap caIdNameMap;

    private final CertificateStore certstore;

    private final List publishers;

    private final boolean onlyRevokedCerts;

    private final int numThreads;

    private final BlockingQueue queue = new ArrayBlockingQueue<>(1000);

    private final AtomicBoolean stopMe = new AtomicBoolean(false);

    private ProcessLog processLog;

    CertRepublisher(final NameId ca, final X509Cert caCert, final CaIdNameMap caIdNameMap,
            final CertificateStore certstore, final List publishers,
            final boolean onlyRevokedCerts, final int numThreads) {
        this.ca = ParamUtil.requireNonNull("ca", ca);
        this.caCert = ParamUtil.requireNonNull("caCert", caCert);
        this.caIdNameMap = ParamUtil.requireNonNull("caIdNameMap", caIdNameMap);
        this.certstore = ParamUtil.requireNonNull("certstore", certstore);
        this.publishers = ParamUtil.requireNonEmpty("publishers", publishers);
        this.onlyRevokedCerts = onlyRevokedCerts;
        this.numThreads = ParamUtil.requireMin("numThreads", numThreads, 1);
    }

    boolean republish() {
        try {
            return republish0();
        } finally {
            if (processLog != null) {
                processLog.finish();
                processLog.printTrailer();
            }
        }
    }

    private boolean republish0() {
        long total;
        try {
            total = certstore.getCountOfCerts(ca, onlyRevokedCerts);
        } catch (OperationException ex) {
            LogUtil.error(LOG, ex, "could not getCountOfCerts");
            return false;
        }
        processLog = new ProcessLog(total);
        processLog.printHeader();

        ExecutorService executor = Executors.newFixedThreadPool(numThreads + 1);
        List consumers = new ArrayList<>(numThreads);
        AtomicBoolean stopMe = new AtomicBoolean(false);
        for (int i = 0; i < numThreads; i++) {
            CertRepublishConsumer consumer = new CertRepublishConsumer();
            consumers.add(consumer);
        }

        CertRepublishProducer producer = new CertRepublishProducer();

        executor.execute(producer);
        for (CertRepublishConsumer consumer : consumers) {
            executor.execute(consumer);
        }

        executor.shutdown();
        boolean successful = true;

        while (true) {
            processLog.printStatus();

            if (successful) {
                if (producer.failed) {
                    successful = false;
                }

                if (successful) {
                    for (CertRepublishConsumer consumer : consumers) {
                        if (consumer.failed) {
                            successful = false;
                            break;
                        }
                    }
                }

                if (!successful) {
                    stopMe.set(true);
                    LOG.warn("failed");
                }
            }

            try {
                boolean terminated = executor.awaitTermination(1, TimeUnit.SECONDS);
                if (terminated) {
                    break;
                }
            } catch (InterruptedException ex) {
                stopMe.set(true);
                LogUtil.warn(LOG, ex, "interrupted: " + ex.getMessage());
            }
        }

        if (successful) {
            if (producer.failed) {
                successful = false;
            }

            if (successful) {
                for (CertRepublishConsumer consumer : consumers) {
                    if (consumer.failed) {
                        successful = false;
                        break;
                    }
                }
            }

            if (!successful) {
                LOG.warn("failed");
            }
        }

        return successful;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy