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

com.aconex.scrutineer.IdAndVersionStreamVerifier Maven / Gradle / Ivy

package com.aconex.scrutineer;

import java.util.Iterator;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;

import org.apache.log4j.Logger;

public class IdAndVersionStreamVerifier {

    private static final Logger LOG = LogUtils.loggerForThisClass();

    private final ExecutorService executorService = Executors.newFixedThreadPool(2, new NamedDaemonThreadFactory("StreamOpener"));

    //CHECKSTYLE:OFF
    @SuppressWarnings("PMD.NcssMethodCount")
    public void verify(final IdAndVersionStream primaryStream, final IdAndVersionStream secondayStream, final IdAndVersionStreamVerifierListener idAndVersionStreamVerifierListener) {
        long numItems = 0;
        long begin = System.currentTimeMillis();

        try {

            parallelOpenStreamsAndWait(primaryStream, secondayStream);

            Iterator primaryIterator = primaryStream.iterator();
            Iterator secondaryIterator = secondayStream.iterator();

            IdAndVersion primaryItem = next(primaryIterator);
            IdAndVersion secondaryItem = next(secondaryIterator);

            while (primaryItem != null && secondaryItem != null) {
                if (primaryItem.equals(secondaryItem)) {
                    primaryItem = next(primaryIterator);
                    secondaryItem = next(secondaryIterator);
                } else if (primaryItem.getId().equals(secondaryItem.getId())) {
                    idAndVersionStreamVerifierListener.onVersionMisMatch(primaryItem, secondaryItem);
                    primaryItem = next(primaryIterator);
                    secondaryItem = next(secondaryIterator);
                } else if (primaryItem.compareTo(secondaryItem) < 0) {
                    idAndVersionStreamVerifierListener.onMissingInSecondaryStream(primaryItem);
                    primaryItem = next(primaryIterator);
                } else {
                    idAndVersionStreamVerifierListener.onMissingInPrimaryStream(secondaryItem);
                    secondaryItem = next(secondaryIterator);
                }
                numItems++;
            }

            while (primaryItem != null) {
                idAndVersionStreamVerifierListener.onMissingInSecondaryStream(primaryItem);
                primaryItem = next(primaryIterator);
                numItems++;
            }

            while (secondaryItem != null) {
                idAndVersionStreamVerifierListener.onMissingInPrimaryStream(secondaryItem);
                secondaryItem = next(secondaryIterator);
                numItems++;
            }
        } finally {
            closeWithoutThrowingException(primaryStream);
            closeWithoutThrowingException(secondayStream);
        }
        LogUtils.infoTimeTaken(LOG, begin, numItems, "Completed verification");
    }
    //CHECKSTYLE:ON

    private void parallelOpenStreamsAndWait(IdAndVersionStream primaryStream, IdAndVersionStream secondaryStream) {
        Future primaryOpenCall = executorService.submit(new OpenStreamRunner(primaryStream));
        Future secondaryOpenCall = executorService.submit(new OpenStreamRunner(secondaryStream));

        getAllFutures(primaryOpenCall, secondaryOpenCall);
    }

    private void getAllFutures(Future... futures) {
        try {
            for (Future future : futures) {
                future.get();
            }
        } catch (Exception e) {
            throw new IllegalStateException("Failed to open one or both of the streams in parallel", e);
        }
    }

    private IdAndVersion next(Iterator iterator) {
        if (iterator.hasNext()) {
            return iterator.next();
        } else {
            return null;
        }
    }

    private void closeWithoutThrowingException(IdAndVersionStream idAndVersionStream) {
        try {
            idAndVersionStream.close();
        } catch (Exception e) {
            LogUtils.warn(LOG, "Unable to close IdAndVersionStream", e);
        }
    }

    private static class OpenStreamRunner implements Runnable {
        private final IdAndVersionStream primaryStream;

        public OpenStreamRunner(IdAndVersionStream primaryStream) {
            this.primaryStream = primaryStream;
        }

        @Override
        public void run() {
            primaryStream.open();
        }
    }

    private static class NamedDaemonThreadFactory implements ThreadFactory {
        private final String namePrefix;
        private final AtomicInteger threadCount = new AtomicInteger();

        public NamedDaemonThreadFactory(String namePrefix) {
            this.namePrefix = namePrefix;
        }

        @Override
        public Thread newThread(Runnable command) {
            Thread thread = new Thread(command, namePrefix + "-" + threadCount.incrementAndGet());
            thread.setDaemon(true);
            return thread;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy