Package org.carrot2.util.pool

Source Code of org.carrot2.util.pool.FixedSizePool

/*
* Carrot2 project.
*
* Copyright (C) 2002-2014, Dawid Weiss, Stanisław Osiński.
* All rights reserved.
*
* Refer to the full license file "carrot2.LICENSE"
* in the root folder of the repository checkout or at:
* http://www.carrot2.org/carrot2.LICENSE
*/

package org.carrot2.util.pool;

import java.util.ArrayList;
import java.util.Map;
import java.util.Map.Entry;

import org.carrot2.util.Pair;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

/**
* An object pool storing hard references to a fixed number of instantiated objects at the
* given key. The objects are never released from the pool until {@link #dispose()} is
* called.
*/
public final class FixedSizePool<T, P> implements IParameterizedPool<T, P>
{
    private Map<Pair<Class<? extends T>, P>, ArrayList<T>> instances = Maps.newHashMap();

    private IInstantiationListener<T, P> instantiationListener;
    private IActivationListener<T, P> activationListener;
    private IPassivationListener<T, P> passivationListener;
    private IDisposalListener<T, P> disposalListener;

    /**
     * Each key in the pool points to a list of instances. This field defines how many
     * components are kept for each key.
     */
    private final int listSizePerKey;

    /**
     * @param listSizePerKey Each key in the pool points to a list of instances. This
     *            field defines how many components are kept for each key.
     */
    public FixedSizePool(int listSizePerKey)
    {
        if (listSizePerKey <= 0)
            throw new IllegalArgumentException("Pool size must be greater than zero: "
                + listSizePerKey);
        this.listSizePerKey = listSizePerKey;
    }

    /**
     * Initialize listeners.
     */
    public void init(IInstantiationListener<T, P> objectInstantiationListener,
        IActivationListener<T, P> objectActivationListener,
        IPassivationListener<T, P> objectPassivationListener,
        IDisposalListener<T, P> objectDisposalListener)
    {
        this.instantiationListener = objectInstantiationListener;
        this.activationListener = objectActivationListener;
        this.passivationListener = objectPassivationListener;
        this.disposalListener = objectDisposalListener;
    }

    @SuppressWarnings("unchecked")
    public <I extends T> I borrowObject(Class<I> clazz, P parameter)
        throws InstantiationException, IllegalAccessException
    {
        final I instance;
        synchronized (this)
        {
            if (instances == null)
            {
                throw new IllegalStateException("The pool has already been disposed of");
            }

            Pair<Class<? extends T>, P> key = new Pair<Class<? extends T>, P>(clazz,
                parameter);

            ArrayList<T> list = instances.get(key);
            if (list == null)
            {
                instances.put(key, list = createInstancePool(clazz, parameter));
            }

            while (list.size() == 0)
            {
                try
                {
                    this.wait();
                    if (this.instances == null)
                    {
                        throw new InstantiationException("Pool disposed while waiting.");
                    }
                }
                catch (InterruptedException e)
                {
                    throw new InstantiationException(
                        "Interrupted while waiting for the object pool: " + clazz + ", "
                            + parameter);
                }
            }

            instance = (I) list.remove(list.size() - 1);
        }

        if (activationListener != null)
        {
            activationListener.activate(instance, parameter);
        }
        return instance;
    }

    /*
     *
     */
    public void returnObject(T object, P parameter)
    {
        if (object == null) throw new IllegalArgumentException(
            "Null could not have been acquired from this pool.");

        if (passivationListener != null)
        {
            passivationListener.passivate(object, parameter);
        }

        synchronized (this)
        {
            if (instances == null)
            {
                // disposed, silently ignore.
                return;
            }

            @SuppressWarnings({
                "unchecked", "rawtypes"
            })
            final Pair<T, P> key = new Pair(object.getClass(), parameter);
            final ArrayList<T> list = instances.get(key);
            if (list == null)
            {
                throw new IllegalStateException(
                    "Returning an object that was never borrowed: " + object);
            }

            // The object must not be on the list at this point. The pool won't be large
            // enough for the linear scan to be a problem.
            for (T reference : list)
            {
                if (reference != null && reference == object)
                {
                    throw new IllegalStateException("Object has not been borrowed");
                }
            }

            list.add(object);

            // Notify all because we can't be sure notify() will awake a thread waiting
            // on the same key. We could do two nested monitors here, but it makes little
            // sense (minor performance overhead).
            this.notifyAll();
        }
    }

    /*
     *
     */
    public void dispose()
    {
        synchronized (this)
        {
            if (this.instances == null)
            {
                // Already disposed.
                return;
            }

            final Map<Pair<Class<? extends T>, P>, ArrayList<T>> instancesRef = this.instances;
            this.instances = null;
            this.notifyAll();

            for (Entry<Pair<Class<? extends T>, P>, ArrayList<T>> entry : instancesRef.entrySet())
            {
                for (T instance : entry.getValue())
                {
                    if (instance != null && disposalListener != null)
                    {
                        disposalListener.dispose(instance, entry.getKey().objectB);
                    }
                }
            }
        }
    }

    /*
     *
     */
    private <I extends T> ArrayList<T> createInstancePool(Class<I> clazz,
        P parameter) throws InstantiationException, IllegalAccessException
    {
        ArrayList<T> list = Lists.newArrayList();
        for (int i = 0; i < listSizePerKey; i++)
        {
            I instance = clazz.newInstance();
            if (instantiationListener != null)
            {
                instantiationListener.objectInstantiated(instance, parameter);
            }
            list.add(instance);
        }
        return list;
    }
}
TOP

Related Classes of org.carrot2.util.pool.FixedSizePool

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.