LocalObjectPool.java

/*
 * Copyright (c) 2001, Zoltan Farkas All Rights Reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
package org.spf4j.pool.impl;

import java.util.ArrayList;
import org.spf4j.pool.ObjectBorower;
import org.spf4j.pool.ObjectCreationException;
import org.spf4j.pool.ObjectDisposeException;
import org.spf4j.pool.ObjectPool;
import org.spf4j.pool.ObjectReturnException;
import org.spf4j.pool.SmartObjectPool;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.locks.ReentrantLock;

/**
 *
 * @author zoly
 */
public final class LocalObjectPool<T> implements ObjectPool<T>, ObjectBorower<ObjectHolder<T>> {

    private final Queue<ObjectHolder<T>> localObjects;
    private final Map<T, ObjectHolder<T>> borrowedObjects;
    private final SmartObjectPool<ObjectHolder<T>> globalPool;
    private int reqReturnObjects;
    private final Thread thread;
    private final ReentrantLock lock;

    public LocalObjectPool(final SmartObjectPool<ObjectHolder<T>> globalPool) {
        localObjects = new LinkedList<ObjectHolder<T>>();
        borrowedObjects = new HashMap<T, ObjectHolder<T>>();
        this.globalPool = globalPool;
        reqReturnObjects = 0;
        thread = Thread.currentThread();
        lock = new ReentrantLock();
    }

    @Override
    public T borrowObject() throws ObjectCreationException,
            InterruptedException, TimeoutException {
        lock.lock();
        try {
            T object;
            ObjectHolder<T> objectHolder;
            do {
                if (localObjects.isEmpty()) {
                    objectHolder = globalPool.borrowObject(this);
                } else {
                    objectHolder = localObjects.remove();
                }
                object = objectHolder.borrowOrCreateObjectIfPossible();
            } while (object == null);
            borrowedObjects.put(object, objectHolder);
            return object;
        } finally {
            lock.unlock();
        }
    }

    @Override
    public void returnObject(final T object, final Exception e) throws ObjectReturnException, ObjectDisposeException {
        lock.lock();
        try {
            ObjectHolder holder = borrowedObjects.remove(object);
            if (holder == null) {
                throw new IllegalArgumentException("Object " + object + " has not been borrowed from this pool");
            }
            try {
                holder.returnObject(object, e);
            } finally {
                if (reqReturnObjects > 0) {
                    reqReturnObjects--;
                    globalPool.returnObject(holder, this);
                } else {
                    localObjects.add(holder);
                }
            }
            
        } finally {
            lock.unlock();
        }
    }

    @Override
    public void dispose() throws ObjectDisposeException {
        throw new UnsupportedOperationException("LocalPool dispose is not supported");
    }

    @Override
    public boolean scan(final ScanHandler<ObjectHolder<T>> handler) throws Exception {
        lock.lock();
        try {
            for (ObjectHolder<T> object : localObjects) {
                if (!handler.handle(object)) {
                    return false;
                }
            }
            return true;
        } finally {
            lock.unlock();
        }
    }

    @Override
    public Object requestReturnObject() {
        boolean acquired = lock.tryLock();
        if (acquired) {
            try {
                ObjectHolder<T> objectHolder = returnObjectIfNotInUse();
                if (objectHolder != null) {
                    return objectHolder;
                } else {
                    reqReturnObjects++;
                    return ObjectBorower.REQUEST_MADE;
                }
            } finally {
                lock.unlock();
            }
        } else {
            return null;
        }
    }

    @Override
    public ObjectHolder<T> returnObjectIfNotInUse() {
        boolean acquired = lock.tryLock();
        if (acquired) {
            try {
                if (!localObjects.isEmpty()) {
                    return localObjects.remove();
                } else {
                    return null;
                }
            } finally {
                lock.unlock();
            }
        } else {
            return null;
        }
    }
    
    
    @Override
    public Collection<ObjectHolder<T>> returnObjectsIfNotInUse() {
        boolean acquired = lock.tryLock();
        if (acquired) {
            try {
                if (!localObjects.isEmpty()) {
                    Collection<ObjectHolder<T>> result = new ArrayList<ObjectHolder<T>>(localObjects);
                    localObjects.clear();
                    return result;
                } else {
                    return null;
                }
            } finally {
                lock.unlock();
            }
        } else {
            return null;
        }
    }
    

    @Override
    public Collection<ObjectHolder<T>> returnObjectsIfNotNeeded() {
        boolean acquired = lock.tryLock();
        if (acquired) {
            try {
                if (!thread.isAlive()) {
                    if (!borrowedObjects.isEmpty()) {
                        throw new IllegalStateException("Objects not returned by dead thread: " + borrowedObjects);
                    }
                    return localObjects;
                }
                return null;
            } finally {
                lock.unlock();
            }
        } else {
            return null;
        }
    }

    @Override
    public String toString() {
        return "LocalObjectPool{" + "localObjects=" + localObjects + ", borrowedObjects="
                + borrowedObjects + ", reqReturnObjects=" + reqReturnObjects + ", thread=" + thread + '}';
    }
}