Pool.java

package info.smart_tools.smartactors.core.pool;

import info.smart_tools.smartactors.core.ipool.IPool;
import info.smart_tools.smartactors.core.ipool.exception.PoolPutException;
import info.smart_tools.smartactors.core.ipool.exception.PoolTakeException;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Supplier;


/**
 * Implementation of {@link info.smart_tools.smartactors.core.ipool.IPool}
 */
public class Pool implements IPool {
    private final ArrayBlockingQueue<Object> freeItems;
    private AtomicInteger freeItemsCounter = new AtomicInteger();

    /**
     * Local function for creation new instances of items
     */
    private Supplier<Object> creationFunction;

    /**
     * Constructs new Pool
     * @param maxItems the maximum of active items.
     * @param func the function for creating new instances of items
     */
    public Pool(final Integer maxItems, final Supplier<Object>  func) {
        if (func == null) {
            throw new IllegalArgumentException("Function must be not null");
        }
        if (maxItems <= 0) {
            throw new IllegalArgumentException("Count of max items mast be more 0");
        }
        this.freeItems = new ArrayBlockingQueue<>(maxItems);
        this.freeItemsCounter.set(maxItems);
        this.creationFunction = func;
    }

    /**
     * Get a value by the key from the scope.
     * @throws PoolTakeException if error was occurred
     * @return Object from pool
     */
    public Object take() throws PoolTakeException {
        if (freeItemsCounter.getAndDecrement() <= 0) {
            freeItemsCounter.getAndIncrement();
            throw new PoolTakeException("Reached limit of items for this pool.");
        }

        try {
            Object result = freeItems.poll();
            if (result == null) {
                result = creationFunction.get();
            }

            return result;
        } catch (Exception e) {
            freeItemsCounter.getAndIncrement();
            throw new PoolTakeException("Failed to get item", e);
        }
    }

    /**
     * Stores a value to the pool.
     * @param item the item that now free.
     * @throws PoolPutException if any error occurred
     */
    public void put(final Object item) throws PoolPutException {
        try {
            if (freeItems.size() >= freeItemsCounter.get()) {
                freeItems.add(item);
                freeItemsCounter.getAndIncrement();
            }
        } catch (Exception e) {
            throw new PoolPutException("Error was occurred", e);
        }
    }
}