Package org.apache.geronimo.connector.outbound

Source Code of org.apache.geronimo.connector.outbound.SinglePoolConnectionInterceptor$PoolDeque

/**
*
* Copyright 2003-2005 The Apache Software Foundation
*
*  Licensed under the Apache License, Version 2.0 (the "License");
*  you may not use this file except in compliance with the License.
*  You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
*  limitations under the License.
*/

package org.apache.geronimo.connector.outbound;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Arrays;
import javax.resource.ResourceException;
import javax.resource.spi.ManagedConnection;

/**
* SinglePoolConnectionInterceptor chooses a single connection from the pool.  If selectOneAssumeMatch
* is true, it simply returns the selected connection.
* THIS SHOULD BE USED ONLY IF MAXIMUM SPEED IS ESSENTIAL AND YOU HAVE THOROUGLY CHECKED THAT
* MATCHING WOULD SUCCEED ON THE SELECTED CONNECTION. (i.e., read the docs on your connector
* to find out how matching works)
* If selectOneAssumeMatch is false, it checks with the ManagedConnectionFactory that the
* selected connection does match before returning it: if not it throws an exception.
*
* @version $Rev: 355877 $ $Date: 2005-12-11 03:48:27 +0100 (Sun, 11 Dec 2005) $
*/
public class SinglePoolConnectionInterceptor extends AbstractSinglePoolConnectionInterceptor {


    private boolean selectOneAssumeMatch;

    private PoolDeque pool;

    public SinglePoolConnectionInterceptor(final ConnectionInterceptor next,
                                           int maxSize,
                                           int minSize,
                                           int blockingTimeoutMilliseconds,
                                           int idleTimeoutMinutes,
                                           boolean selectOneAssumeMatch) {
        super(next, maxSize, minSize, blockingTimeoutMilliseconds, idleTimeoutMinutes);
        pool = new PoolDeque(maxSize);
        this.selectOneAssumeMatch = selectOneAssumeMatch;
    }

    protected void internalGetConnection(ConnectionInfo connectionInfo) throws ResourceException {
        synchronized (pool) {
            if (destroyed) {
                throw new ResourceException("ManagedConnection pool has been destroyed");
            }
               
            ManagedConnectionInfo newMCI = null;
            if (pool.isEmpty()) {
                next.getConnection(connectionInfo);
                connectionCount++;
                if (log.isTraceEnabled()) {
                    log.trace("Returning new connection " + connectionInfo.getManagedConnectionInfo());
                }
                return;
            } else {
                newMCI = pool.removeLast();
            }
            if (connectionCount < minSize) {
                timer.schedule(new FillTask(connectionInfo), 10);
            }
            if (selectOneAssumeMatch) {
                connectionInfo.setManagedConnectionInfo(newMCI);
                if (log.isTraceEnabled()) {
                    log.trace("Returning pooled connection without checking matching " + connectionInfo.getManagedConnectionInfo());
                }
                return;
            }
            try {
                ManagedConnectionInfo mci = connectionInfo.getManagedConnectionInfo();
                ManagedConnection matchedMC =
                        newMCI
                        .getManagedConnectionFactory()
                        .matchManagedConnections(Collections.singleton(newMCI.getManagedConnection()),
                                mci.getSubject(),
                                mci.getConnectionRequestInfo());
                if (matchedMC != null) {
                    connectionInfo.setManagedConnectionInfo(newMCI);
                    if (log.isTraceEnabled()) {
                        log.trace("Returning pooled connection " + connectionInfo.getManagedConnectionInfo());
                    }
                    return;
                } else {
                    //matching failed.
                    ConnectionInfo returnCI = new ConnectionInfo();
                    returnCI.setManagedConnectionInfo(newMCI);
                    returnConnection(returnCI,
                            ConnectionReturnAction.RETURN_HANDLE);
                    throw new ResourceException("The pooling strategy does not match the MatchManagedConnections implementation.  Please investigate and reconfigure this pool");
                }
            } catch (ResourceException e) {
                //something is wrong: destroy connection, rethrow, release permit
                ConnectionInfo returnCI = new ConnectionInfo();
                returnCI.setManagedConnectionInfo(newMCI);
                returnConnection(returnCI,
                        ConnectionReturnAction.DESTROY);
                throw e;
            }
        }
    }

    protected void internalDestroy() {
        synchronized (pool) {
            while (!pool.isEmpty()) {
                ManagedConnection mc = pool.removeLast().getManagedConnection();
                if (mc != null) {
                    try {
                        mc.destroy();
                    }
                    catch (ResourceException re) { } // ignore
                }
            }
        }
    }

    protected boolean internalReturn(ConnectionInfo connectionInfo, ConnectionReturnAction connectionReturnAction) {
        ManagedConnectionInfo mci = connectionInfo.getManagedConnectionInfo();
        ManagedConnection mc = mci.getManagedConnection();
        try {
            mc.cleanup();
        } catch (ResourceException e) {
            connectionReturnAction = ConnectionReturnAction.DESTROY;
        }
        boolean wasInPool = false;
        synchronized (pool) {
            // a bit redundant with returnConnection check in AbstractSinglePoolConnectionInterceptor,
            // but checking here closes a small timing hole...
            if (destroyed) {
                try {
                    mc.destroy();
                }
                catch (ResourceException re) { } // ignore
                return pool.remove(mci);
            }
               
            if (shrinkLater > 0) {
                //nothing can get in the pool while shrinkLater > 0, so wasInPool is false here.
                connectionReturnAction = ConnectionReturnAction.DESTROY;
                shrinkLater--;
            } else if (connectionReturnAction == ConnectionReturnAction.RETURN_HANDLE) {
                mci.setLastUsed(System.currentTimeMillis());
                pool.add(mci);
                return wasInPool;
            } else {
                wasInPool = pool.remove(mci);
            }
        }
        //we must destroy connection.
        next.returnConnection(connectionInfo, connectionReturnAction);
        connectionCount--;
        return wasInPool;
    }

    public int getPartitionMaxSize() {
        return pool.capacity();
    }

    protected void transferConnections(int maxSize, int shrinkNow) {
        //1st example: copy 0 (none)
        //2nd example: copy 10 (all)
        PoolDeque oldPool = pool;
        pool = new PoolDeque(maxSize);
        //since we have replaced pool already, pool.remove will be very fast:-)
        for (int i = 0; i < shrinkNow; i++) {
            ConnectionInfo killInfo = new ConnectionInfo(oldPool.peek(i));
            internalReturn(killInfo, ConnectionReturnAction.DESTROY);
        }
        for (int i = shrinkNow; i < connectionCount; i++) {
            pool.add(oldPool.peek(i));
        }
    }

    public int getIdleConnectionCount() {
        return pool.currentSize();
    }


    protected void getExpiredManagedConnectionInfos(long threshold, ArrayList killList) {
        synchronized (pool) {
            for (int i = 0; i < pool.currentSize(); i++) {
                ManagedConnectionInfo mci = pool.peek(i);
                if (mci.getLastUsed() < threshold) {
                    killList.add(mci);
                }
            }
        }
    }

    protected boolean addToPool(ManagedConnectionInfo mci) {
        boolean added;
        synchronized (pool) {
            connectionCount++;
            added = getPartitionMaxSize() > getIdleConnectionCount();
            if (added) {
                pool.add(mci);
            }
        }
        return added;
    }

    static class PoolDeque {

        private final ManagedConnectionInfo[] deque;
        private final int first = 0;
        private int last = -1;

        public PoolDeque(int size) {
            deque = new ManagedConnectionInfo[size];
        }

        //internal
        public boolean isEmpty() {
            return first > last;
        }

        //internal
        public void add(ManagedConnectionInfo mci) {
            if (last == deque.length - 1) {
                throw new IllegalStateException("deque is full: contents: " + Arrays.asList(deque));
            }
            deque[++last] = mci;
        }

        //internal
        public ManagedConnectionInfo peek(int i) {
            if (i < first || i > last) {
                throw new IllegalStateException("index is out of current range");
            }
            return deque[i];
        }

        //internal
        public ManagedConnectionInfo removeLast() {
            if (isEmpty()) {
                throw new IllegalStateException("deque is empty");
            }

            return deque[last--];
        }

        //internal
        public boolean remove(ManagedConnectionInfo mci) {
            for (int i = first; i <= last; i++) {
                if (deque[i] == mci) {
                    for (int j = i + 1; j <= last; j++) {
                        deque[j - 1] = deque[j];
                    }
                    last--;
                    return true;
                }

            }
            return false;
        }

        //internal
        public int capacity() {
            return deque.length;
        }

        //internal
        public int currentSize() {
            return last - first + 1;
        }
    }

}
TOP

Related Classes of org.apache.geronimo.connector.outbound.SinglePoolConnectionInterceptor$PoolDeque

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.