TrackedLimitedResourcePool.java

package eu.javaexperience.resource.pool;


import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

import eu.javaexperience.asserts.AssertArgument;
import eu.javaexperience.interfaces.simple.SimpleGet;
import eu.javaexperience.semantic.references.MayNull;

public class TrackedLimitedResourcePool<T> implements TrackedResourcePool<T>
{
	protected final ConcurrentLinkedQueue<T> free = new ConcurrentLinkedQueue<>();
	
	protected final AtomicInteger issued = new AtomicInteger();
	
	protected final SimpleGet<T> factory;
	
	protected final int limit;
	
	protected final Semaphore limiter;
	
	@Override
	public int getIssuedResourcesCount()
	{
		return issued.get();
	}
	
	public TrackedLimitedResourcePool(SimpleGet<T> factory, int limit)
	{
		AssertArgument.assertNotNull(this.factory = factory, "factory");
		AssertArgument.assertGreaterOrEqualsThan(this.limit = limit, 0, "limit");
		limiter = new Semaphore(limit);
	}
	
	@Override
	public IssuedResource<T> acquireResource() throws InterruptedException
	{
		return tryAcquireResource(0, null);
	}
	
	@Override
	public void releaseResource(IssuedResource<T> resource)
	{
		AssertArgument.assertNotNull(resource, "resource");
		if(resource.pool != this)
			throw new IllegalArgumentException("The resource acquired from other resource pool");
		
		free.add(resource.getResource());
		issued.decrementAndGet();
		limiter.release();
	}
	
	@Override
	public int getFreeResourcesCount()
	{
		return free.size();
	}

	@Override
	public int getResourceLimitCount()
	{
		return limit;
	}

	@Override
	public @MayNull IssuedResource<T> tryAcquireResource(long paramLong, TimeUnit paramTimeUnit) throws InterruptedException
	{
		if(paramTimeUnit == null)
			limiter.acquire();
		else if(!limiter.tryAcquire(paramLong, paramTimeUnit))
			return null;
		
		T ret = free.poll();
		if(ret == null)
		{
			ret = factory.get();
		}

		issued.incrementAndGet();
		return new IssuedResource<>(this, ret);
	}

	@Override
	public @MayNull IssuedResource<T> pollResource()
	{
		T ret = free.poll();
		if(null == ret)
		{
			return null;
		}
		
		issued.incrementAndGet();
		return new IssuedResource<>(this, ret);
	}

	@Override
	public void destroyResource(IssuedResource<T> resource)
	{
		if(!resource.issued)
		{
			throw new RuntimeException("Resource released, can't be destroyed");
		}
		resource.issued = false;
		resource.resource = null;
		issued.decrementAndGet();
	}
}