/* $Id: IConnectionThrottler.java 1650913 2015-01-11 16:40:01Z kwright $ */

/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.manifoldcf.core.interfaces;

import java.util.*;

/** An IConnectionThrottler object is not thread-local.  It gates connection
* creation and pool management.
* The underlying model is a pool of connections.  A connection gets pulled off the pool and
* used to perform a fetch.  If there are insufficient connections in the pool, and there is
* sufficient capacity to create a new connection, a connection will be created instead.
* When the fetch is done, the connection is returned, and then there is a decision whether
* or not to put the connection back into the pool, or to destroy it.  Finally, the pool is
* periodically evaluated, and connections may be destroyed if either they have expired,
* or the allocated connections are still over capacity.
*
* This object does not in itself contain a connection pool - but it is intended to assist
* in the management of that pool.  Specifically, it tracks connections that are in the
* pool, and connections that are handed out for use, and performs ALL the waiting needed
* due to the pool being empty and/or the number of active connections being at or over
* the quota.
*/
public interface IConnectionThrottler
{
  public static final String _rcsid = "@(#)$Id: IConnectionThrottler.java 1650913 2015-01-11 16:40:01Z kwright $";

  // For grabbing a connection for use
  
  /** Get the connection from the pool */
  public final static int CONNECTION_FROM_POOL = 0;
  /** Create a connection */
  public final static int CONNECTION_FROM_CREATION = 1;
  /** Pool shutting down */
  public final static int CONNECTION_FROM_NOWHERE = -1;
  
  /** Get permission to grab a connection for use.  If this object believes there is a connection
  * available in the pool, it will update its pool size variable and return   If not, this method
  * evaluates whether a new connection should be created.  If neither condition is true, it
  * waits until a connection is available.
  *@return whether to take the connection from the pool, or create one, or whether the
  * throttler is being shut down.
  */
  public int waitConnectionAvailable()
    throws InterruptedException;

  /** Get permission to grab a connection for use.  If this object believes there is a connection
  * available in the pool, it will update its pool size variable and return   If not, this method
  * evaluates whether a new connection should be created.  If neither condition is true, it
  * waits until a connection is available.
  *@return whether to take the connection from the pool, or create one, or whether the
  * throttler is being shut down.
  */
  public int waitConnectionAvailable(IBreakCheck breakCheck)
    throws InterruptedException, BreakException;

  /** For a new connection, obtain the fetch throttler to use for the connection.
  * If the result from waitConnectionAvailable() is CONNECTION_FROM_CREATION,
  * the calling code is expected to create a connection using the result of this method.
  *@return the fetch throttler for a new connection.
  */
  public IFetchThrottler getNewConnectionFetchThrottler();
  
  /** This method indicates whether a formerly in-use connection should be placed back
  * in the pool or destroyed.
  *@return true if the connection should not be put into the pool but should instead
  *  simply be destroyed.  If true is returned, the caller MUST call noteConnectionDestroyed()
  *  after the connection is destroyed in order for the bookkeeping to work.  If false
  *  is returned, the caller MUST call noteConnectionReturnedToPool() after the connection
  *  is returned to the pool.
  */
  public boolean noteReturnedConnection();
  
  /** This method calculates whether a connection should be taken from the pool and destroyed
  /* in order to meet quota requirements.  If this method returns
  /* true, you MUST remove a connection from the pool, and you MUST call
  /* noteConnectionDestroyed() afterwards.
  *@return true if a pooled connection should be destroyed.  If true is returned, the
  * caller MUST call noteConnectionDestroyed() (below) in order for the bookkeeping to work.
  */
  public boolean checkDestroyPooledConnection();
  
  /** Connection expiration is tricky, because even though a connection may be identified as
  * being expired, at the very same moment it could be handed out in another thread.  So there
  * is a natural race condition present.
  * The way the connection throttler deals with that is to allow the caller to reserve a connection
  * for expiration.  This must be called BEFORE the actual identified connection is removed from the
  * connection pool.  If the value returned by this method is "true", then a connection MUST be removed
  * from the pool and destroyed, whether or not the identified connection is actually still available for
  * destruction or not.
  *@return true if a connection from the pool can be expired.  If true is returned, noteConnectionDestruction()
  *  MUST be called once the connection has actually been destroyed.
  */
  public boolean checkExpireConnection();
  
  /** Note that a connection has been returned to the pool.  Call this method after a connection has been
  * placed back into the pool and is available for use.
  */
  public void noteConnectionReturnedToPool();
  
  /** Note that a connection has been destroyed.  Call this method ONLY after noteReturnedConnection()
  * or checkDestroyPooledConnection() returns true, AND the connection has been already
  * destroyed.
  */
  public void noteConnectionDestroyed();
  
}
