/**
 *  Copyright 2010 Wallace Wadge
 *
 *    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 com.jolbox.bonecp;

import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Periodically checks for connections to see if the connection has expired.
 * @author wwadge
 *
 */
public class ConnectionMaxAgeThread implements Runnable {

	/** Max no of ms to wait before a connection that isn't used is killed off. */
	private long maxAgeInMs;
	/** Partition being handled. */
	private ConnectionPartition partition;
	/** Scheduler handle. **/
	private ScheduledExecutorService scheduler;
	/** Handle to connection pool. */
	private BoneCP pool;
	/** Logger handle. */
	protected static Logger logger = LoggerFactory.getLogger(ConnectionTesterThread.class);

	/** Constructor
	 * @param connectionPartition partition to work on
	 * @param scheduler Scheduler handler.
	 * @param pool pool handle
	 * @param maxAgeInMs Threads older than this are killed off 
	 */
	protected ConnectionMaxAgeThread(ConnectionPartition connectionPartition, ScheduledExecutorService scheduler, 
			BoneCP pool, long maxAgeInMs){
		this.partition = connectionPartition;
		this.scheduler = scheduler;
		this.maxAgeInMs = maxAgeInMs;
		this.pool = pool;
	}


	/** Invoked periodically. */
	public void run() {
		ConnectionHandle connection = null;
		long tmp;
		long nextCheckInMs = this.maxAgeInMs;

		int partitionSize= this.partition.getAvailableConnections();
		long currentTime = System.currentTimeMillis();
		for (int i=0; i < partitionSize; i++){
			try {
				connection = this.partition.getFreeConnections().poll();

				if (connection != null){
					connection.setOriginatingPartition(this.partition);

					tmp = this.maxAgeInMs - (currentTime - connection.getConnectionCreationTimeInMs()); 

					if (tmp < nextCheckInMs){
						nextCheckInMs = tmp; 
					}

					if (connection.isExpired(currentTime)){
						// kill off this connection
						closeConnection(connection);
						continue;
					}


					this.pool.putConnectionBackInPartition(connection);

					Thread.sleep(20L); // test slowly, this is not an operation that we're in a hurry to deal with...
				}

			} catch (Exception e) {
				if (this.scheduler.isShutdown()){
					logger.debug("Shutting down connection max age thread.");
					break;
				} 
				logger.error("Connection max age thread exception.", e);
			}

		} // throw it back on the queue

		if (!this.scheduler.isShutdown()){
			this.scheduler.schedule(this, nextCheckInMs, TimeUnit.MILLISECONDS);
		}

	}


	/** Closes off this connection
	 * @param connection to close
	 */
	protected void closeConnection(ConnectionHandle connection) {
		if (connection != null) {
			try {
				connection.internalClose();
			} catch (Throwable t) {
				logger.error("Destroy connection exception", t);
			} finally {
				this.pool.postDestroyConnection(connection);
			}
		}
}
}

@@ -1273,16 +1273,96 @@
 P pool;%0A
+%09/** If true, we're operating in a LIFO fashion. */ %0A%09private boolean lifoMode;%0A
 %09/** Log
@@ -1372,24 +1372,24 @@
  handle. */%0A
-
 %09protected s
@@ -1665,16 +1665,81 @@
 ed off %0A
+%09 * @param lifoMode if true, we're running under a lifo fashion.%0A
 %09 */%0A%09pr
@@ -1874,24 +1874,42 @@
 g maxAgeInMs
+, boolean lifoMode
 )%7B%0A%09%09this.pa
@@ -2021,16 +2021,44 @@
 = pool;%0A
+%09%09this.lifoMode = lifoMode;%0A
 %09%7D%0A%0A%0A%09/*
@@ -2804,16 +2804,302 @@
 %09%09%09%09%7D%0A%0A%0A
+%09%09%09%09%09%0A%09%09%09%09%09if (this.lifoMode)%7B%0A%09%09%09%09%09%09// we can't put it back normally or it will end up in front again.%0A%09%09%09%09%09%09if (!((LIFOQueue%3CConnectionHandle%3E)connection.getOriginatingPartition().getFreeConnections()).offerLast(connection))%7B%0A%09%09%09%09%09%09%09connection.internalClose();%0A%09%09%09%09%09%09%7D%0A%09%09%09%09%09%7D else %7B%0A%09
 %09%09%09%09%09thi
@@ -3143,24 +3143,32 @@
 onnection);%0A
+%09%09%09%09%09%7D%0A%0A
 %0A%09%09%09%09%09Thread

Allow connectionmaxage thread to utilize lifo mode correctly.