# PooledSequenceIdentifierProvider.java

    package org.codefilarete.stalactite.engine.idprovider;

    import java.time.Duration;
    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.List;
    import java.util.concurrent.Executor;

    import org.codefilarete.stalactite.engine.SeparateTransactionExecutor;
    import org.codefilarete.stalactite.mapping.id.sequence.hilo.PooledHiLoSequence;
    import org.codefilarete.stalactite.mapping.id.sequence.hilo.PooledHiLoSequenceOptions;
    import org.codefilarete.stalactite.sql.Dialect;

    /**
     * Provider which will get its values from a database sequence-like (not a real SQL sequence): HiLo algorithm is used
     * by {@link PooledHiLoSequence}
     *
     * @author Guillaume Mary
     * @see PooledHiLoSequence
     */
    public class PooledSequenceIdentifierProvider extends PooledIdentifierProvider<Long> {

    	private final PooledHiLoSequence sequenceIdentifierGenerator;

    	/**
    	 * @param initialValues the initial values for filling this queue. Can be empty, not null.
    	 * @param threshold the threshold below (excluded) which the backgound service is called for filling this queue
    	 * @param executor the executor capable of running a background filling of this queue
    	 * @param timeOut the time-out after which the {@link #giveNewIdentifier()} gives up and returns null because of an empty queue
    	 * @param sequenceIdentifierGenerator the sequence accessor that will provide values
    	 */
    	public PooledSequenceIdentifierProvider(Collection<Long> initialValues, int threshold, Executor executor, Duration timeOut,
    											PooledHiLoSequence sequenceIdentifierGenerator) {
    		super(initialValues, threshold, executor, timeOut);
    		this.sequenceIdentifierGenerator = sequenceIdentifierGenerator;
    	}

    	/**
    	 * @param initialValues the initial values for filling this queue. Can be empty, not null.
    	 * @param threshold the threshold below (excluded) which the backgound service is called for filling this queue
    	 * @param executor the executor capable of running a background filling of this queue
    	 * @param timeOut the time-out after which the {@link #giveNewIdentifier()} gives up and returns null because of an empty queue
    	 * @param options parameter for the internal {@link PooledHiLoSequence}
    	 * @param dialect parameter for the internal {@link PooledHiLoSequence}
    	 * @param separateTransactionExecutor parameter for the internal {@link PooledHiLoSequence}
    	 * @param jdbcBatchSize parameter for the internal {@link PooledHiLoSequence}
    	 * @see PooledHiLoSequence#PooledHiLoSequence(PooledHiLoSequenceOptions, Dialect, SeparateTransactionExecutor, int)
    	 */
    	public PooledSequenceIdentifierProvider(Collection<Long> initialValues, int threshold, Executor executor, Duration timeOut,
    											PooledHiLoSequenceOptions options, Dialect dialect, SeparateTransactionExecutor separateTransactionExecutor, int jdbcBatchSize) {
    		this(initialValues, threshold, executor, timeOut, new PooledHiLoSequence(options, dialect, separateTransactionExecutor, jdbcBatchSize));
    	}

    	@Override
    	protected Collection<Long> retrieveSomeValues() {
    		// Our sequence generator is already pooled, but we don't now really how, so we take benefit from our queue by transfering sequence values
    		// to us. Moreover since we are supposed to be asynchronous, even if the sequence pooling is not perfect it doesn't matter.

    		// We decide to sink all possible values from the sequence
    		int poolSize = sequenceIdentifierGenerator.getOptions().getPoolSize();
    		List<Long> result = new ArrayList<>(poolSize);
    		for (int i = 0; i < poolSize; i++) {
    			result.add(sequenceIdentifierGenerator.next());
    		}
    		return result;
    	}
    }