All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.xsocket.connection.NonBlockingConnectionPool Maven / Gradle / Ivy

There is a newer version: 2.8.15
Show newest version
/*
 * Copyright (c) xlightweb.org, 2006 - 2010. 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
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * Please refer to the LGPL license at: http://www.gnu.org/copyleft/lesser.txt
 * The latest copy of this software may be found on http://www.xsocket.org/
 */
package org.xsocket.connection;


import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketTimeoutException;
import java.nio.BufferOverflowException;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.FileChannel;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
import java.nio.channels.FileChannel.MapMode;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TimerTask;
import java.util.Map.Entry;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.net.ssl.SSLContext;

import org.xsocket.DataConverter;
import org.xsocket.Execution;
import org.xsocket.ILifeCycle;
import org.xsocket.MaxReadSizeExceededException;





/**
 * A connection pool implementation.

* * This class is thread safe
* *
 *  // create a unbound connection pool
 *  NonBlockingConnectionPool pool = new NonBlockingConnectionPool();
 *
 *  INonBlockingCinnection con = null;
 *
 *  try {
 *     // retrieve a connection (if no connection is in pool, a new one will be created)
 *     con = pool.getNonBlockingConnection(host, port);
 *     con.write("Hello");
 *     ...
 *
 *     // always close the connection! (the connection will be returned into the connection pool)
 *     con.close();
 *
 * 	} catch (IOException e) {
 *     if (con != null) {
 *        try {
 *          // if the connection is invalid -> destroy it (it will not return into the pool)
 *          pool.destroy(con);
 *        } catch (Exception ignore) { }
 *     }
 *  }
 * 
* * @author [email protected] */ public final class NonBlockingConnectionPool implements IConnectionPool { private static final Logger LOG = Logger.getLogger(NonBlockingConnectionPool.class.getName()); private static final long MIN_REMAINING_MILLIS_TO_IDLE_TIMEOUT = 3 * 1000; private static final long MIN_REMAINING_MILLIS_TO_CONNECTION_TIMEOUT = 3 * 1000; private static final int CONNECT_MAX_TRIALS = Integer.parseInt(System.getProperty("org.xsocket.connection.connectionpool.maxtrials", "3")); private static final int CONNECT_RETRY_WAIT_TIME_MILLIS = Integer.parseInt(System.getProperty("org.xsocket.connection.connectionpool.retrywaittimemillis", "10")); // is open flag private final AtomicBoolean isOpen = new AtomicBoolean(true); // ssl support private final SSLContext sslContext; // settings private final AtomicInteger maxActive = new AtomicInteger(IConnectionPool.DEFAULT_MAX_ACTIVE); private final AtomicInteger maxActivePerServer = new AtomicInteger(IConnectionPool.DEFAULT_MAX_ACTIVE_PER_SERVER); private final AtomicInteger maxIdle = new AtomicInteger(IConnectionPool.DEFAULT_MAX_IDLE); private final AtomicLong maxWaitMillis = new AtomicLong(IConnectionPool.DEFAULT_MAX_WAIT_MILLIS); private final AtomicInteger poolIdleTimeoutMillis = new AtomicInteger(IConnectionPool.DEFAULT_IDLE_TIMEOUT_MILLIS); private final AtomicInteger lifeTimeoutMillis = new AtomicInteger(IConnectionPool.DEFAULT_LIFE_TIMEOUT_MILLIS); private final Object limitGuard = new Object(); private int numInitializingConnections = 0; private final Map initializingConnectionMap = new HashMap(); // pool management private final Pool pool = new Pool(); private final Object retrieveGuard = new Object(); private Executor workerpool = NonBlockingConnection.getDefaultWorkerpool(); // timeout checker private static final int DEFAULT_WATCHDOG_CHECK_PERIOD = 30 * 1000; private final Watchog watchdog; // listeners private final List listeners = new ArrayList(); // statistics private final AtomicInteger countRejectedConnections = new AtomicInteger(0); private final AtomicInteger countUndetectedDisconnect = new AtomicInteger(0); private final AtomicInteger countPendingGet = new AtomicInteger(0); private final AtomicInteger countCreated = new AtomicInteger(0); private final AtomicInteger countDestroyed = new AtomicInteger(0); private final AtomicInteger countRemainingMillisToIdleTimeoutToSmall = new AtomicInteger(0); private final AtomicInteger countRemainingConnectionToIdleTimeoutToSmall = new AtomicInteger(0); private final AtomicInteger countCreationError = new AtomicInteger(0); private final AtomicInteger countIdleTimeout = new AtomicInteger(0); private final AtomicInteger countConnectionTimeout = new AtomicInteger(0); private final AtomicInteger countTimeoutPooledIdle = new AtomicInteger(0); private final AtomicInteger countTimeoutPooledLifetime = new AtomicInteger(0); /** * constructor * */ public NonBlockingConnectionPool() { this(null); } /** * constructor * * @param sslContext the ssl context or null if ssl should not be used */ public NonBlockingConnectionPool(SSLContext sslContext) { this(sslContext, DEFAULT_WATCHDOG_CHECK_PERIOD); } /** * constructor * * @param sslContext the ssl context or null if ssl should not be used */ NonBlockingConnectionPool(SSLContext sslContext, int watchdogCheckPeriod) { this.sslContext = sslContext; watchdog = new Watchog(); IoProvider.getTimer().schedule(watchdog, watchdogCheckPeriod, watchdogCheckPeriod); } /** * get a pool connection for the given address. If no free connection is in the pool, * a new one will be created * * @param host the server address * @param port the server port * @return the connection * @throws SocketTimeoutException if the wait timeout has been reached (this will only been thrown if wait time has been set) * @throws IOException if an exception occurs * @throws MaxConnectionsExceededException if the max number of active connections (per server) is reached */ public INonBlockingConnection getNonBlockingConnection(String host, int port) throws IOException, SocketTimeoutException, MaxConnectionsExceededException { return getConnection(new InetSocketAddress(host, port), null, workerpool, toInt(IConnection.DEFAULT_CONNECTION_TIMEOUT_MILLIS), maxWaitMillis.get(), false); } /** * get a pool connection for the given address. If no free connection is in the pool, * a new one will be created * * @param host the server address * @param port the server port * @param isSSL true, if ssl connection * @return the connection * @throws SocketTimeoutException if the wait timeout has been reached (this will only been thrown if wait time has been set) * @throws IOException if an exception occurs * @throws MaxConnectionsExceededException if the max number of active connections (per server) is reached */ public INonBlockingConnection getNonBlockingConnection(String host, int port, boolean isSSL) throws IOException, SocketTimeoutException, MaxConnectionsExceededException { return getConnection(new InetSocketAddress(host, port), null, workerpool, toInt(IConnection.DEFAULT_CONNECTION_TIMEOUT_MILLIS), maxWaitMillis.get(), isSSL); } /** * get a pool connection for the given address. If no free connection is in the pool, * a new one will be created * * @param host the server address * @param port the server port * @param connectTimeoutMillis the connection timeout * @return the connection * @throws SocketTimeoutException if the wait timeout has been reached (this will only been thrown if wait time has been set) * @throws IOException if an exception occurs * @throws MaxConnectionsExceededException if the max number of active connections (per server) is reached */ public INonBlockingConnection getNonBlockingConnection(String host, int port, int connectTimeoutMillis) throws IOException, SocketTimeoutException, MaxConnectionsExceededException { return getConnection(new InetSocketAddress(host, port), null, workerpool, connectTimeoutMillis, maxWaitMillis.get(), false); } /** * get a pool connection for the given address. If no free connection is in the pool, * a new one will be created * * @param host the server address * @param port the server port * @param connectTimeoutMillis the connection timeout * @param isSSL true, if ssl connection * @return the connection * @throws SocketTimeoutException if the wait timeout has been reached (this will only been thrown if wait time has been set) * @throws IOException if an exception occurs * @throws MaxConnectionsExceededException if the max number of active connections (per server) is reached */ public INonBlockingConnection getNonBlockingConnection(String host, int port, int connectTimeoutMillis, boolean isSSL) throws IOException, SocketTimeoutException, MaxConnectionsExceededException { return getConnection(new InetSocketAddress(host, port), null, workerpool, connectTimeoutMillis, maxWaitMillis.get(), isSSL); } /** * get a pool connection for the given address. If no free connection is in the pool, * a new one will be created * * @param address the server address * @return the connection * @throws SocketTimeoutException if the wait timeout has been reached (this will only been thrown if wait time has been set) * @throws IOException if an exception occurs * @throws MaxConnectionsExceededException if the max number of active connections (per server) is reached */ public INonBlockingConnection getNonBlockingConnection(InetSocketAddress address) throws IOException, SocketTimeoutException, MaxConnectionsExceededException { return getConnection(address, null, workerpool, toInt(IConnection.DEFAULT_CONNECTION_TIMEOUT_MILLIS), maxWaitMillis.get(), false); } /** * get a pool connection for the given address. If no free connection is in the pool, * a new one will be created * * @param address the server address * @param port the sever port * @return the connection * @throws SocketTimeoutException if the wait timeout has been reached (this will only been thrown if wait time has been set) * @throws IOException if an exception occurs * @throws MaxConnectionsExceededException if the max number of active connections (per server) is reached */ public INonBlockingConnection getNonBlockingConnection(InetAddress address, int port) throws IOException, SocketTimeoutException, MaxConnectionsExceededException { return getConnection(new InetSocketAddress(address, port), null, workerpool, toInt(IConnection.DEFAULT_CONNECTION_TIMEOUT_MILLIS), maxWaitMillis.get(), false); } /** * get a pool connection for the given address. If no free connection is in the pool, * a new one will be created * * @param address the server address * @param port the sever port * @param isSSL true, if ssl connection * @return the connection * @throws SocketTimeoutException if the wait timeout has been reached (this will only been thrown if wait time has been set) * @throws IOException if an exception occurs * @throws MaxConnectionsExceededException if the max number of active connections (per server) is reached */ public INonBlockingConnection getNonBlockingConnection(InetAddress address, int port, boolean isSSL) throws IOException, SocketTimeoutException, MaxConnectionsExceededException { return getConnection(new InetSocketAddress(address, port), null, workerpool, toInt(IConnection.DEFAULT_CONNECTION_TIMEOUT_MILLIS), maxWaitMillis.get(), isSSL); } /** * get a pool connection for the given address. If no free connection is in the pool, * a new one will be created * * @param address the server address * @param port the server port * @param connectTimeoutMillis the connection timeout * @return the connection * @throws SocketTimeoutException if the wait timeout has been reached (this will only been thrown if wait time has been set) * @throws IOException if an exception occurs * @throws MaxConnectionsExceededException if the max number of active connections (per server) is reached */ public INonBlockingConnection getNonBlockingConnection(InetAddress address, int port, int connectTimeoutMillis) throws IOException, SocketTimeoutException, MaxConnectionsExceededException { return getConnection(new InetSocketAddress(address, port), null, workerpool, connectTimeoutMillis, maxWaitMillis.get(), false); } /** * get a pool connection for the given address. If no free connection is in the pool, * a new one will be created * * @param address the server address * @param port the server port * @param connectTimeoutMillis the connection timeout * @param isSSL true, if ssl connection * @return the connection * @throws SocketTimeoutException if the wait timeout has been reached (this will only been thrown if wait time has been set) * @throws IOException if an exception occurs * @throws MaxConnectionsExceededException if the max number of active connections (per server) is reached */ public INonBlockingConnection getNonBlockingConnection(InetAddress address, int port, int connectTimeoutMillis, boolean isSSL) throws IOException, SocketTimeoutException, MaxConnectionsExceededException { return getConnection(new InetSocketAddress(address, port), null, workerpool, connectTimeoutMillis, maxWaitMillis.get(), isSSL); } /** * get a pool connection for the given address. If no free connection is in the pool, * a new one will be created * * @param address the server address * @param port the server port * @param appHandler the application handler (supported: IConnectHandler, IDisconnectHandler, IDataHandler, IIdleTimeoutHandler and IConnectionTimeoutHandler) * @return the connection * @throws SocketTimeoutException if the wait timeout has been reached (this will only been thrown if wait time has been set) * @throws IOException if an exception occurs * @throws MaxConnectionsExceededException if the max number of active connections (per server) is reached */ public INonBlockingConnection getNonBlockingConnection(InetAddress address, int port, IHandler appHandler) throws IOException, SocketTimeoutException, MaxConnectionsExceededException { return getConnection(new InetSocketAddress(address, port), appHandler, workerpool, toInt(IConnection.DEFAULT_CONNECTION_TIMEOUT_MILLIS), maxWaitMillis.get(), false); } /** * get a pool connection for the given address. If no free connection is in the pool, * a new one will be created * * @param address the server address * @param port the server port * @param appHandler the application handler (supported: IConnectHandler, IDisconnectHandler, IDataHandler, IIdleTimeoutHandler and IConnectionTimeoutHandler) * @param isSSL true, if ssl connection * @return the connection * @throws SocketTimeoutException if the wait timeout has been reached (this will only been thrown if wait time has been set) * @throws IOException if an exception occurs * @throws MaxConnectionsExceededException if the max number of active connections (per server) is reached */ public INonBlockingConnection getNonBlockingConnection(InetAddress address, int port, IHandler appHandler, boolean isSSL) throws IOException, SocketTimeoutException, MaxConnectionsExceededException { return getConnection(new InetSocketAddress(address, port), appHandler, workerpool, toInt(IConnection.DEFAULT_CONNECTION_TIMEOUT_MILLIS), maxWaitMillis.get(), isSSL); } /** * get a pool connection for the given address. If no free connection is in the pool, * a new one will be created * * @param host the server address * @param port the server port * @param appHandler the application handler (supported: IConnectHandler, IDisconnectHandler, IDataHandler, IIdleTimeoutHandler and IConnectionTimeoutHandler) * @return the connection * @throws SocketTimeoutException if the wait timeout has been reached (this will only been thrown if wait time has been set) * @throws IOException if an exception occurs * @throws MaxConnectionsExceededException if the max number of active connections (per server) is reached */ public INonBlockingConnection getNonBlockingConnection(String host, int port, IHandler appHandler) throws IOException, SocketTimeoutException, MaxConnectionsExceededException { return getConnection(new InetSocketAddress(host, port), appHandler, workerpool, toInt(IConnection.DEFAULT_CONNECTION_TIMEOUT_MILLIS), maxWaitMillis.get(), false); } /** * get a pool connection for the given address. If no free connection is in the pool, * a new one will be created * * @param host the server address * @param port the server port * @param appHandler the application handler (supported: IConnectHandler, IDisconnectHandler, IDataHandler, IIdleTimeoutHandler and IConnectionTimeoutHandler) * @param isSSL true, if ssl connection * @return the connection * @throws SocketTimeoutException if the wait timeout has been reached (this will only been thrown if wait time has been set) * @throws IOException if an exception occurs * @throws MaxConnectionsExceededException if the max number of active connections (per server) is reached */ public INonBlockingConnection getNonBlockingConnection(String host, int port, IHandler appHandler, boolean isSSL) throws IOException, SocketTimeoutException, MaxConnectionsExceededException { return getConnection(new InetSocketAddress(host, port), appHandler, workerpool, toInt(IConnection.DEFAULT_CONNECTION_TIMEOUT_MILLIS), maxWaitMillis.get(), isSSL); } /** * get a pool connection for the given address. If no free connection is in the pool, * a new one will be created * * @param address the server address * @param port the server port * @param appHandler the application handler (supported: IConnectHandler, IDisconnectHandler, IDataHandler, IIdleTimeoutHandler and IConnectionTimeoutHandler) * @param connectTimeoutMillis the connection creation timeout * @return the connection * @throws SocketTimeoutException if the wait timeout has been reached (this will only been thrown if wait time has been set) * @throws IOException if an exception occurs * @throws MaxConnectionsExceededException if the max number of active connections (per server) is reached */ public INonBlockingConnection getNonBlockingConnection(InetAddress address, int port, IHandler appHandler, int connectTimeoutMillis) throws IOException, SocketTimeoutException, MaxConnectionsExceededException { return getConnection(new InetSocketAddress(address, port), appHandler, workerpool, connectTimeoutMillis, maxWaitMillis.get(), false); } /** * get a pool connection for the given address. If no free connection is in the pool, * a new one will be created * * @param address the server address * @param port the server port * @param appHandler the application handler (supported: IConnectHandler, IDisconnectHandler, IDataHandler, IIdleTimeoutHandler and IConnectionTimeoutHandler) * @param connectTimeoutMillis the connection creation timeout * @param isSSL true, if ssl connection * @return the connection * @throws SocketTimeoutException if the wait timeout has been reached (this will only been thrown if wait time has been set) * @throws IOException if an exception occurs * @throws MaxConnectionsExceededException if the max number of active connections (per server) is reached */ public INonBlockingConnection getNonBlockingConnection(InetAddress address, int port, IHandler appHandler, int connectTimeoutMillis, boolean isSSL) throws IOException, SocketTimeoutException, MaxConnectionsExceededException { return getConnection(new InetSocketAddress(address, port), appHandler, workerpool, connectTimeoutMillis, maxWaitMillis.get(), isSSL); } /** * get a pool connection for the given address. If no free connection is in the pool, * a new one will be created

* * This method is thread safe * * @param address the server address * @param port the sever port * @param appHandler the application handler (supported: IConnectHandler, IDisconnectHandler, IDataHandler, IIdleTimeoutHandler and ConnectionTimeoutHandler) * @param workerPool the worker pool to use * @param connectTimeoutMillis the connection creation timeout * @return the connection * @throws SocketTimeoutException if the wait timeout has been reached (this will only been thrown if wait time has been set) * @throws IOException if an exception occurs * @throws MaxConnectionsExceededException if the max number of active connections (per server) is reached */ public INonBlockingConnection getNonBlockingConnection(InetAddress address, int port, IHandler appHandler, Executor workerPool, int connectTimeoutMillis) throws IOException, SocketTimeoutException, MaxConnectionsExceededException { return getConnection(new InetSocketAddress(address, port), appHandler, workerPool, connectTimeoutMillis, maxWaitMillis.get(), false); } /** * get a pool connection for the given address. If no free connection is in the pool, * a new one will be created

* * This method is thread safe * * @param address the server address * @param port the sever port * @param appHandler the application handler (supported: IConnectHandler, IDisconnectHandler, IDataHandler, IIdleTimeoutHandler and ConnectionTimeoutHandler) * @param workerPool the worker pool to use * @param connectTimeoutMillis the connection creation timeout * @param isSSL true, if ssl connection * @return the connection * @throws SocketTimeoutException if the wait timeout has been reached (this will only been thrown if wait time has been set) * @throws IOException if an exception occurs * @throws MaxConnectionsExceededException if the max number of active connections (per server) is reached */ public INonBlockingConnection getNonBlockingConnection(InetAddress address, int port, IHandler appHandler, Executor workerPool, int connectTimeoutMillis, boolean isSSL) throws IOException, SocketTimeoutException, MaxConnectionsExceededException { return getConnection(new InetSocketAddress(address, port), appHandler, workerPool, connectTimeoutMillis, maxWaitMillis.get(), isSSL); } private int toInt(long l) { if (l > Integer.MAX_VALUE) { return Integer.MAX_VALUE; } else { return (int) l; } } private INonBlockingConnection getConnection(InetSocketAddress address, IHandler appHandler, Executor workerPool, int connectTimeoutMillis, long waitTimeMillis, boolean isSSL) throws IOException, SocketTimeoutException, MaxConnectionsExceededException, MaxConnectionsExceededException { // is limitation activated? if ((maxActive.get() != Integer.MAX_VALUE) || (maxActivePerServer.get() != Integer.MAX_VALUE)) { InetAddress addr = address.getAddress(); synchronized (limitGuard) { if ((pool.getNumActive() + numInitializingConnections) >= maxActive.get()) { if(LOG.isLoggable(Level.FINE)) { LOG.fine("max active connections " + maxActive.get() + " exceeded"); } countRejectedConnections.incrementAndGet(); throw new MaxConnectionsExceededException("max active connections " + maxActive.get() + " exceeded"); } // limit per host activated? if (maxActivePerServer.get() != Integer.MAX_VALUE) { Integer connectionAddr = initializingConnectionMap.get(addr); if (connectionAddr == null) { connectionAddr = 0; } if (pool.isActiveExceeded(addr, (maxActivePerServer.get() - connectionAddr))) { if(LOG.isLoggable(Level.FINE)) { LOG.fine("max active connections " + maxActivePerServer.get() + " (initializing: " + connectionAddr + ") to " + addr + " exceeded"); } countRejectedConnections.incrementAndGet(); throw new MaxConnectionsExceededException("max active connections " + maxActivePerServer.get() + " (initializing: " + connectionAddr + ") to " + addr + " exceeded"); } connectionAddr++; initializingConnectionMap.put(addr, connectionAddr); } numInitializingConnections++; } try { return getConnectionUnbound(address, appHandler, workerPool, connectTimeoutMillis, waitTimeMillis, isSSL); } finally { synchronized (limitGuard) { numInitializingConnections--; Integer connectionAddr = initializingConnectionMap.get(addr); if (connectionAddr != null) { connectionAddr--; if (connectionAddr <= 0) { initializingConnectionMap.remove(addr); } else { initializingConnectionMap.put(addr, connectionAddr); } } } } // no unlimited } else { return getConnectionUnbound(address, appHandler, workerPool, connectTimeoutMillis, waitTimeMillis, isSSL); } } private INonBlockingConnection getConnectionUnbound(InetSocketAddress address, IHandler appHandler, Executor workerPool, int connectTimeoutMillis, long waitTimeMillis, boolean isSSL) throws IOException, SocketTimeoutException, MaxConnectionsExceededException, MaxConnectionsExceededException { if (isOpen.get()) { // try to get a connection from the pool NativeConnectionHolder nativeConnectionHolder; do { // try to get a pooled native connection nativeConnectionHolder = pool.getAndRemoveIdleConnection(address, isSSL); // got it? if (nativeConnectionHolder != null) { // reset resource (connection will be closed if invalid) boolean isValid = nativeConnectionHolder.isVaild(System.currentTimeMillis(), true); if (isValid && nativeConnectionHolder.getConnection().reset()) { if (LOG.isLoggable(Level.FINE)) { LOG.fine("got connection from pool (" + pool.toString() + ", idleTimeoutMillis=" + getPooledMaxIdleTimeMillis() + ", lifeTimeout=" + getPooledMaxLifeTimeMillis() + "): " + nativeConnectionHolder.getConnection()); } return new NonBlockingConnectionProxy(nativeConnectionHolder, appHandler); } else { if (LOG.isLoggable(Level.FINE)) { LOG.fine("get a invalid connection try another one"); } } } } while (nativeConnectionHolder != null); // no resource available in pool -> create a new one nativeConnectionHolder = newNativeConnection(address, workerPool, connectTimeoutMillis, CONNECT_MAX_TRIALS, CONNECT_RETRY_WAIT_TIME_MILLIS, isSSL); return new NonBlockingConnectionProxy(nativeConnectionHolder, appHandler); } else { throw new IOException("pool is already closed"); } } private void returnToIdlePool(NativeConnectionHolder nativeConnectionHolder) { pool.returnIdleConnection(nativeConnectionHolder); if (maxActive.get() < Integer.MAX_VALUE) { wakeupPendingRetrieve(); } } private void wakeupPendingRetrieve() { synchronized (retrieveGuard) { retrieveGuard.notifyAll(); } } private NativeConnectionHolder newNativeConnection(InetSocketAddress address, Executor workerPool, final int creationTimeoutMillis, int maxTrials, int retryWaittimeMillis, boolean isSSL) throws IOException { if (isSSL && (sslContext == null)) { throw new IOException("could not create a SSL connection to " + address.toString() + ". SSLContext is not set"); } long start = System.currentTimeMillis(); int remainingTimeMillis = creationTimeoutMillis; int trials = 0; while (true) { trials++; try { // create a new tcp connection and the assigned holder NativeConnectionHolder nativeConnectionHolder = new NativeConnectionHolder(); NonBlockingConnection pooledConnection = new NonBlockingConnection(address, true, remainingTimeMillis, new HashMap(), sslContext, isSSL, nativeConnectionHolder, workerPool, null); nativeConnectionHolder.init(pooledConnection); return nativeConnectionHolder; } catch (IOException ioe) { countCreationError.incrementAndGet(); // is timeout reached? remainingTimeMillis = creationTimeoutMillis - ((int) (System.currentTimeMillis() - start)); if (remainingTimeMillis <= 0) { if (LOG.isLoggable(Level.FINE)) { LOG.fine("error occured by creating connection to " + address + ". creation timeout " + DataConverter.toFormatedDuration(creationTimeoutMillis) + " reached (trials: " + trials + " maxTrials: " + maxTrials + ")"); } throw new SocketTimeoutException("creation timeout " + creationTimeoutMillis + " millis reached (trials: " + trials + " maxTrials: " + maxTrials + "). Could not connect to " + address + " " + ioe.toString()); } // max trials reached? if (trials >= maxTrials) { throw new SocketTimeoutException("creation failed. Max trials " + maxTrials + " reached. Elapsed time " + DataConverter.toFormatedDuration(System.currentTimeMillis() - start) + " (creation timeout " + DataConverter.toFormatedDuration(creationTimeoutMillis) + "). Could not connect to " + address + " " + ioe.toString()); } else { if (remainingTimeMillis > retryWaittimeMillis) { try { Thread.sleep(retryWaittimeMillis); } catch (InterruptedException ie) { // Restore the interrupted status Thread.currentThread().interrupt(); } retryWaittimeMillis += retryWaittimeMillis; } else { throw new SocketTimeoutException("creation timeout " + creationTimeoutMillis + " millis reached (trials: " + trials + " maxTrials: " + maxTrials + "). Could not connect to " + address + " " + ioe.toString()); } } } } } /** * {@inheritDoc} */ public boolean isOpen() { return isOpen.get(); } /** * {@inheritDoc} */ public void close() { if (isOpen.getAndSet(false)) { pool.close(); watchdog.cancel(); for (ILifeCycle lifeCycle : listeners) { try { lifeCycle.onDestroy(); } catch (IOException ioe) { if (LOG.isLoggable(Level.FINE)) { LOG.fine("exception occured by destroying " + lifeCycle + " " + ioe.toString()); } } } listeners.clear(); // unset references workerpool = null; } } /** * destroy the pool by killing idle and active connections */ public void destroy() { if (isOpen.getAndSet(false)) { pool.destroy(); watchdog.cancel(); for (ILifeCycle lifeCycle : listeners) { try { lifeCycle.onDestroy(); } catch (IOException ioe) { if (LOG.isLoggable(Level.FINE)) { LOG.fine("exception occured by destroying " + lifeCycle + " " + ioe.toString()); } } } listeners.clear(); // unset references workerpool = null; } } /** * {@inheritDoc} */ public void addListener(ILifeCycle listener) { listeners.add(listener); } /** * {@inheritDoc} */ public boolean removeListener(ILifeCycle listener) { boolean result = listeners.remove(listener); return result; } /** * set the worker pool which will be assigned to the connections for call back handling * @param workerpool the worker pool */ public void setWorkerpool(Executor workerpool) { this.workerpool = workerpool; } /** * get the worker pool which will be assigned to the connections for call back handling * @return the worker pool */ public Executor getWorkerpool() { return workerpool; } /** * {@inheritDoc} */ public int getMaxActive() { return maxActive.get(); } /** * {@inheritDoc} */ public int getNumRejectedConnections() { return countRejectedConnections.get(); } /** * {@inheritDoc} */ public void setMaxActive(int maxActive) { if (maxActive < 0) { maxActive = 0; } this.maxActive.set(maxActive); wakeupPendingRetrieve(); } /** * {@inheritDoc} */ public void setMaxActivePerServer(int maxActivePerServer) { if (maxActivePerServer < 0) { maxActivePerServer = 0; } this.maxActivePerServer.set(maxActivePerServer); wakeupPendingRetrieve(); } /** * {@inheritDoc} */ public int getMaxActivePerServer() { return maxActivePerServer.get(); } /** * {@inheritDoc} */ public int getMaxIdle() { return maxIdle.get(); } /** * {@inheritDoc} */ public void setMaxIdle(int maxIdle) { this.maxIdle.set(maxIdle); } /** * {@inheritDoc} */ public int getNumActive() { return pool.getNumActive(); } public List getActiveConnectionInfos() { List result = new ArrayList(); List connectionHolders = pool.newManagedPoolCopy(); connectionHolders.removeAll(pool.newIdleCopySet()); for (NativeConnectionHolder connectionHolder : connectionHolders) { result.add(connectionHolder.toString()); } return result; } public List getIdleConnectionInfos() { List result = new ArrayList(); for (NativeConnectionHolder nativeConnectionHolder : pool.newIdleCopySet()) { result.add(nativeConnectionHolder.toString()); } return result; } /** * {@inheritDoc} */ public int getNumIdle() { return pool.getNumIdle(); } /** * {@inheritDoc} */ public int getNumCreated() { return countCreated.get(); } /** * get the number of the creation errors * * @return the number of creation errors */ public int getNumCreationError() { return countCreationError.get(); } /** * {@inheritDoc} */ public int getNumDestroyed() { return countDestroyed.get(); } int getNumIdleTimeout() { return countIdleTimeout.get(); } int getNumConnectionTimeout() { return countConnectionTimeout.get(); } int getNumPoolIdleTimeout() { return countTimeoutPooledIdle.get(); } int getNumPoolLifetimeTimeout() { return countTimeoutPooledLifetime.get(); } /** * {@inheritDoc} */ public int getNumTimeoutPooledMaxIdleTime() { return countTimeoutPooledIdle.get(); } /** * {@inheritDoc} */ public int getNumTimeoutPooledMaxLifeTime() { return countTimeoutPooledLifetime.get(); } int getNumUndetectedDisconnect() { return countUndetectedDisconnect.get(); } /** * {@inheritDoc} */ public int getPooledMaxIdleTimeMillis() { return poolIdleTimeoutMillis.get(); } /** * {@inheritDoc} */ public void setPooledMaxIdleTimeMillis(int idleTimeoutMillis) { this.poolIdleTimeoutMillis.set(idleTimeoutMillis); } /** * {@inheritDoc} */ public int getPooledMaxLifeTimeMillis() { return lifeTimeoutMillis.get(); } /** * {@inheritDoc} */ public void setPooledMaxLifeTimeMillis(int lifeTimeoutMillis) { this.lifeTimeoutMillis.set(lifeTimeoutMillis); } /** * get the current number of pending get operations to retrieve a resource * * @return the current number of pending get operations */ public int getNumPendingGet() { return countPendingGet.get(); } /** * {@inheritDoc} */ public static void destroy(INonBlockingConnection connection) throws IOException { if (connection == null) { if (LOG.isLoggable(Level.FINE)) { LOG.fine("warning trying to destroy a connection. destroy will be ignored"); } return; } if (connection instanceof NonBlockingConnectionProxy) { ((NonBlockingConnectionProxy) connection).destroy(); } else { connection.close(); } } static boolean isDestroyed(INonBlockingConnection connection) { if (connection instanceof NonBlockingConnectionProxy) { return ((NonBlockingConnectionProxy) connection).isDestroyed(); } else { return connection.isOpen(); } } private void checkIdleConnections() { long currentMillis = System.currentTimeMillis(); for (NativeConnectionHolder nativeConnectionHolder : pool.newIdleCopySet()) { if (!nativeConnectionHolder.isVaild(currentMillis, false)) { boolean isRemoved = pool.removeIdleConnection(nativeConnectionHolder); if (isRemoved) { if (LOG.isLoggable(Level.FINE)) { LOG.fine("[" + nativeConnectionHolder.getId() + "] closing connection because it is invalid (e.g. idle timeout, connection timeout reached)"); } nativeConnectionHolder.isVaild(currentMillis, true); // true -> closes the connection nativeConnectionHolder.close(); /// sanity close } } } } @Override public String toString() { StringBuilder sb = new StringBuilder(); try { sb.append("active=" + getNumActive() + ", idle=" + getNumIdle() + " "); sb.append("created=" + countCreated + ", destroyed=" + countDestroyed + " "); sb.append("connectionTimeout=" + countConnectionTimeout + ", idleTimeout=" + countIdleTimeout + " ("); sb.append("maxActive=" + maxActive + ", maxIdle=" + maxIdle + ", maxWaitTimeMillis=" + maxWaitMillis + ", "); sb.append("poolIdleTimeout=" + poolIdleTimeoutMillis + ", poollifetimeTimeout=" + lifeTimeoutMillis + ")"); } catch (Exception ignore) { } return sb.toString(); } private final class Watchog extends TimerTask { @Override public void run() { try { checkIdleConnections(); } catch (Throwable t) { if (LOG.isLoggable(Level.FINE)) { LOG.fine("error occured by checking connections " + t.toString()); } } } } private static final class Pool { private final ArrayList managedPool = new ArrayList(); private final HashMap> idlePool = new HashMap>(); private boolean isOpen = true; public void register(NativeConnectionHolder nativeConnectionHolder) { if (isOpen) { synchronized (this) { managedPool.add(nativeConnectionHolder); } if (LOG.isLoggable(Level.FINE)) { LOG.fine("[" + nativeConnectionHolder.getId() + "] added to managed pool (active=" + getNumActive() + ", idle=" + getNumIdle() + ")"); } } else { if (LOG.isLoggable(Level.FINE)) { LOG.fine("ignore registering connection " + nativeConnectionHolder.toString() + " because pool is already closed"); } } } public boolean remove(NativeConnectionHolder nativeConnectionHolder) { boolean isRemoved = false; if (isOpen) { removeIdleConnection(nativeConnectionHolder); synchronized (this) { isRemoved = managedPool.remove(nativeConnectionHolder); } if (LOG.isLoggable(Level.FINE)) { if (isRemoved) { LOG.fine("[" + nativeConnectionHolder.getId() + "] connection removed from managed pool (active=" + getNumActive() + ", idle=" + getNumIdle() + ")"); } else { LOG.fine("[" + nativeConnectionHolder.getId() + "] could not removed connection from managed pool. Connection already removed? (active=" + getNumActive() + ", idle=" + getNumIdle() + ")"); } } } return isRemoved; } public boolean removeIdleConnection(NativeConnectionHolder connectionHolder) { if (isOpen) { synchronized (this) { List idleList = idlePool.get(connectionHolder.getAddress()); if (idleList != null) { for (NativeConnectionHolder nativeConnectionHolder : idleList) { if (nativeConnectionHolder == connectionHolder) { boolean isRemoved = idleList.remove(nativeConnectionHolder); if (idleList.isEmpty()) { idlePool.remove(connectionHolder.getAddress()); } return isRemoved; } } } } } return false; } public NativeConnectionHolder getAndRemoveIdleConnection(InetSocketAddress address, boolean isSSL) { if (isOpen) { synchronized (this) { List idleList = idlePool.get(address); if (idleList != null) { for (NativeConnectionHolder nativeConnectionHolder : idleList) { if (nativeConnectionHolder.isSSL == isSSL) { idleList.remove(nativeConnectionHolder); if (idleList.isEmpty()) { idlePool.remove(address); } if (LOG.isLoggable(Level.FINE)) { LOG.fine("[" + nativeConnectionHolder.getId() + "] got from idle pool (active=" + getNumActive() + ", idle=" + getNumIdle() + ")"); } return nativeConnectionHolder; } } } } } return null; } public void returnIdleConnection(NativeConnectionHolder nativeConnectionHolder) { if (isOpen) { InetSocketAddress address = nativeConnectionHolder.getAddress(); synchronized (this) { List idleList = idlePool.get(address); if (idleList == null) { idleList = new ArrayList(); idlePool.put(address, idleList); } if (!idleList.contains(nativeConnectionHolder)) { idleList.add(nativeConnectionHolder); } else { if (LOG.isLoggable(Level.FINE)) { LOG.fine("[" + nativeConnectionHolder.getId() + "] will not be returned to pool because it already exits (active=" + getNumActive() + ", idle=" + getNumIdle() + ")"); } } } if (LOG.isLoggable(Level.FINE)) { LOG.fine("[" + nativeConnectionHolder.getId() + "] added to idle pool (active=" + getNumActive() + ", idle=" + getNumIdle() + ")"); } } else { if (LOG.isLoggable(Level.FINE)) { LOG.fine("[" + nativeConnectionHolder.getId() + "] will not be returned to pool, because pool is already closed. destroying connection"); } nativeConnectionHolder.close(); } } public void close() { synchronized (this) { if (isOpen) { isOpen = false; } else { return; } } List idleSet = newIdleCopySet(); if (LOG.isLoggable(Level.FINE)) { LOG.fine("closing " + idleSet.size() + " idle conection(s); " + managedPool.size() + " connection(s) stay open unmanaged"); } for (NativeConnectionHolder nativeConnectionHolder : idleSet) { nativeConnectionHolder.close(); } idlePool.clear(); managedPool.clear(); } public void destroy() { synchronized (this) { if (isOpen) { isOpen = false; } else { return; } } List connections = newManagedPoolCopy(); if (LOG.isLoggable(Level.FINE)) { LOG.fine("closing " + connections.size() + " managed connections"); } for (NativeConnectionHolder nativeConnectionHolder : connections) { nativeConnectionHolder.close(); } synchronized (this) { idlePool.clear(); managedPool.clear(); } } private List newIdleCopySet() { List idleList = new ArrayList(); for (List nativeConnectionHolderList : newIdlePoolCopy().values()) { idleList.addAll(nativeConnectionHolderList); } return idleList; } @SuppressWarnings("unchecked") List newManagedPoolCopy() { List managedPoolCopy = null; synchronized (this) { managedPoolCopy = (List) managedPool.clone(); } return managedPoolCopy; } @SuppressWarnings("unchecked") boolean isActiveExceeded(InetAddress address, int maxSize) { List managedPoolCopy; synchronized (this) { managedPoolCopy = (List) managedPool.clone(); } if (managedPoolCopy.size() < maxSize) { return false; } int managedMatched = 0; for (NativeConnectionHolder holder : managedPoolCopy) { if (holder.getAddress().getAddress().equals(address)) { managedMatched++; } } if (managedMatched < maxSize) { return false; } HashMap> idlePoolCopy; synchronized (this) { idlePoolCopy = (HashMap>) idlePool.clone(); } for (Entry> entry : idlePoolCopy.entrySet()) { if (entry.getKey().getAddress().equals(address)) { managedMatched = managedMatched - entry.getValue().size(); if (managedMatched < maxSize) { return false; } } } return true; } @SuppressWarnings("unchecked") HashMap> newIdlePoolCopy() { HashMap> idlePoolCopy = null; synchronized (this) { idlePoolCopy = (HashMap>) idlePool.clone(); } return idlePoolCopy; } public int getSize() { synchronized (this) { return managedPool.size(); } } public int getNumIdle() { synchronized (this) { return computeNumIdle(); } } public int getNumActive() { synchronized (this) { return (managedPool.size() - computeNumIdle()); } } private int computeNumIdle() { int size = 0; for (List nativeConnectionHolderList : idlePool.values()) { size += nativeConnectionHolderList.size(); } return size; } @Override public String toString() { return "size=" + getSize() + ", active=" + getNumActive(); } } @Execution(Execution.NONTHREADED) private final class NativeConnectionHolder implements IDataHandler, IDisconnectHandler, IConnectionTimeoutHandler, IIdleTimeoutHandler { private final AtomicBoolean isClosed = new AtomicBoolean(false); private final AtomicBoolean isReusable = new AtomicBoolean(true); private final AtomicReference proxyRef = new AtomicReference(null); private NonBlockingConnection connection; private InetSocketAddress address; private boolean isSSL; private int usage = 0; private long creationTimeMillis = System.currentTimeMillis(); private long lastUsageTimeMillis = System.currentTimeMillis(); public void init(NonBlockingConnection connection) { init(connection, new InetSocketAddress(connection.getRemoteAddress(), connection.getRemotePort())); pool.register(this); countCreated.incrementAndGet(); if (LOG.isLoggable(Level.FINE)) { LOG.fine("[" + connection.getId() + "] pooled connection created (" + pool.toString() + ", pooledIdleTimeoutMillis=" + getPooledMaxIdleTimeMillis() + ", pooledLifeTimeout=" + getPooledMaxLifeTimeMillis() + "): " + connection); } } private void init(NonBlockingConnection connection, InetSocketAddress address) { this.address = address; this.connection = connection; isSSL = connection.isSecure(); } String getId() { return connection.getId(); } int getPooledMaxLifeTimeMillis() { return lifeTimeoutMillis.get(); } int getPooledMaxIdleTimeMillis() { return poolIdleTimeoutMillis.get(); } public boolean onData(INonBlockingConnection connection) throws IOException, BufferUnderflowException, MaxReadSizeExceededException { NonBlockingConnectionProxy cp = proxyRef.get(); if (cp != null) { try { return cp.onData(ConnectionUtils.isDispatcherThread()); } catch (MaxReadSizeExceededException mre) { isReusable.set(false); throw mre; } catch (IOException ioe) { isReusable.set(false); throw ioe; } } else { return true; } } public boolean onDisconnect(INonBlockingConnection connection) throws IOException { isReusable.set(false); if (LOG.isLoggable(Level.FINE)) { LOG.fine("onDisconnect occured. Removing connection from pool (" + address.toString() + ") (" + pool.toString() + ", idleTimeoutMillis=" + getPooledMaxIdleTimeMillis() + ", lifeTimeout=" + getPooledMaxLifeTimeMillis() + "): " + connection); } pool.remove(this); try { NonBlockingConnectionProxy cp = proxyRef.get(); if (cp!= null) { return cp.onDisconnect(ConnectionUtils.isDispatcherThread()); } else { if (LOG.isLoggable(Level.FINE)) { LOG.fine("could not call onDisconnect on proxy (proxy already dregistered?)"); } return true; } } finally { countDestroyed.incrementAndGet(); } } public boolean onConnectionTimeout(INonBlockingConnection connection) throws IOException { isReusable.set(false); countConnectionTimeout.incrementAndGet(); if (LOG.isLoggable(Level.FINE)) { LOG.fine("[" + getId() + "] connection timeout occured"); } NonBlockingConnectionProxy cp = proxyRef.get(); if (cp != null) { return cp.onConnectionTimeout(); } else { return false; // let the connection be destroyed } } public boolean onIdleTimeout(INonBlockingConnection connection) throws IOException { isReusable.set(false); countIdleTimeout.incrementAndGet(); if (LOG.isLoggable(Level.FINE)) { LOG.fine("[" + getId() + "] idle timeout (" + DataConverter.toFormatedDuration(getConnection().getIdleTimeoutMillis()) + ") occured"); } NonBlockingConnectionProxy cp = proxyRef.get(); if (cp != null) { return cp.onIdleTimeout(); } else { return false; // let the connection be destroyed } } int getUsage() { return usage; } long getCreationTimeMillis() { return creationTimeMillis; } NonBlockingConnection getConnection() { return connection; } InetSocketAddress getAddress() { return address; } void registerProxy(NonBlockingConnectionProxy proxy) { assert (proxyRef.get() == null); usage++; lastUsageTimeMillis = System.currentTimeMillis(); proxyRef.set(proxy); } void unregister() { proxyRef.set(null); lastUsageTimeMillis = System.currentTimeMillis(); try { // is connected? if (connection.isConnected()) { if (connection.isOpen() && isOpen() && (connection.available() == 0)) { // reset resource boolean isValid = isVaild(System.currentTimeMillis(), true); if (isValid) { // .. and return it to the pool only if max idle size is not reached if ((maxIdle.get() != Integer.MAX_VALUE) || (pool.getNumIdle() >= maxIdle.get())) { return; } boolean isReset = connection.reset(); if (isReset) { if (LOG.isLoggable(Level.FINE)) { LOG.fine("[" + connection.getId() + "] releasing connection (for reuse)"); } returnToIdlePool(this); return; } } } close(); } } catch (Exception e) { // eat and log exception if (LOG.isLoggable(Level.FINE)) { LOG.fine("error occured by releasing a pooled connection (" + address.toString() + ") " + e.toString()); } } } /** * check if the connection is valid * * @return true, if reuseable */ private boolean isVaild(long currentTimeMillis, boolean closeIfInvalid) { // is open? if (isClosed.get()) { if (LOG.isLoggable(Level.FINE)) { LOG.fine("[" + getId() + "] is invalid (closed)"); } return false; } if (!isReusable.get()) { if (closeIfInvalid) { if (LOG.isLoggable(Level.FINE)) { LOG.fine("[" + getId() + "] closing connection because it is marked as non reuseable"); } close(); } return false; } if (!connection.isConnected() || !connection.isOpen()) { if (closeIfInvalid) { if (LOG.isLoggable(Level.FINE)) { LOG.fine("[" + getId() + "] closing connection because it is disconnected or closed"); } close(); } return false; } if (connection.getRemainingMillisToIdleTimeout() < MIN_REMAINING_MILLIS_TO_IDLE_TIMEOUT) { if (closeIfInvalid) { if (LOG.isLoggable(Level.FINE)) { LOG.fine("[" + getId() + "] closing connection because remaining time to idle timeout (" + connection.getRemainingMillisToIdleTimeout() + " millis) is to small"); } countRemainingMillisToIdleTimeoutToSmall.incrementAndGet(); close(); } return false; } if (connection.getRemainingMillisToConnectionTimeout() < MIN_REMAINING_MILLIS_TO_CONNECTION_TIMEOUT) { if (closeIfInvalid) { if (LOG.isLoggable(Level.FINE)) { LOG.fine("[" + getId() + "] closing connection because remaining time to connection timeout (" + connection.getRemainingMillisToConnectionTimeout() + " millis) is to small"); } countRemainingConnectionToIdleTimeoutToSmall.incrementAndGet(); close(); } return false; } if ((poolIdleTimeoutMillis.get() != Integer.MAX_VALUE) && (currentTimeMillis > (lastUsageTimeMillis + poolIdleTimeoutMillis.get()))) { if (closeIfInvalid) { if (LOG.isLoggable(Level.FINE)) { LOG.fine("[" + connection.getId() + "] connection (" + address + ") pool idle timeout reached (" + poolIdleTimeoutMillis + ")"); } countTimeoutPooledIdle.incrementAndGet(); close(); } return false; } if ((lifeTimeoutMillis.get() != Integer.MAX_VALUE) && (currentTimeMillis > (creationTimeMillis + lifeTimeoutMillis.get()))) { if (closeIfInvalid) { if (LOG.isLoggable(Level.FINE)) { LOG.fine("[" + getId() + "] connection (" + address + ") pool life timeout reached (" + lifeTimeoutMillis + ")"); } countTimeoutPooledLifetime.incrementAndGet(); close(); } return false; } return true; } void close() { if (!isClosed.getAndSet(true)) { pool.remove(this); NonBlockingConnection.closeSilence(connection); wakeupPendingRetrieve(); } } @Override public String toString() { StringBuilder sb = new StringBuilder(); try { if (connection.isReceivingSuspended()) { sb.append("[suspended] "); } sb.append(connection.getLocalAddress() + ":" + connection.getLocalPort() + " -> " + connection.getRemoteAddress() + ":" + connection.getRemotePort() + " " + "[" + connection.getId() + "]"); SimpleDateFormat df = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss"); sb.append(" creationTime=" + df.format(getCreationTimeMillis()) + ", ageMillis=" + (System.currentTimeMillis() - creationTimeMillis) + ", elapsedLastUsageMillis=" + (System.currentTimeMillis() - lastUsageTimeMillis) + ", countUsage=" + getUsage() + ", isReusable=" + isReusable.get()); } catch (Exception ignore) { } return sb.toString(); } } private static final class NonBlockingConnectionProxy implements INonBlockingConnection { private volatile boolean isOpen = true; private final AtomicReference nativeConnectionHolderRef = new AtomicReference(null); private final String id; private final AtomicReference handlerAdapterRef = new AtomicReference(null); private final AtomicReference handlerReplaceListenerRef = new AtomicReference(); private Object attachment = null; private boolean isAutoflush = IConnection.DEFAULT_AUTOFLUSH; private final int countReuse; private final long initialSendBytes; private final long initialReceivedBytes; private final long creationTime; private final long elapsedLastUsage; // timeout support private final AtomicBoolean isIdleTimeoutOccured = new AtomicBoolean(false); private final AtomicBoolean isConnectionTimeoutOccured = new AtomicBoolean(false); private final Object disconnectedGuard = false; private boolean isDisconnected = false; NonBlockingConnectionProxy(NativeConnectionHolder holder, IHandler appHandler) throws IOException { initHolder(holder); creationTime = System.currentTimeMillis(); elapsedLastUsage = holder.lastUsageTimeMillis; countReuse = holder.usage; id = holder.getConnection().getId() + "I" + Integer.toHexString(countReuse); initialReceivedBytes = holder.getConnection().getNumberOfReceivedBytes(); initialSendBytes = holder.getConnection().getNumberOfSendBytes(); setHandler(appHandler); holder.registerProxy(this); onConnect(); } private void initHolder(NativeConnectionHolder holder) { nativeConnectionHolderRef.set(holder); holder.getConnection().setAutoflush(false); } private void ensureOpen() { if (!isOpen) { throw new RuntimeException("channel " + getId() + " is closed"); } } public void setHandler(IHandler hdl) throws IOException { ensureOpen(); NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (holder != null) { HandlerAdapter oldHandlerAdapter = handlerAdapterRef.get(); IHandlerChangeListener changeListener = handlerReplaceListenerRef.get(); // call old handler change listener if ((changeListener != null) && (oldHandlerAdapter != null)) { IHandler oldHandler = oldHandlerAdapter.getHandler(); changeListener.onHanderReplaced(oldHandler, hdl); } boolean isChangeListener = false; if (hdl != null) { isChangeListener = (hdl instanceof IHandlerChangeListener); } HandlerAdapter adapter = HandlerAdapter.newInstance(hdl); if (hdl instanceof IHandlerChangeListener) { handlerReplaceListenerRef.set((IHandlerChangeListener) hdl); } boolean callDisconnect = false; synchronized (disconnectedGuard) { handlerAdapterRef.set(adapter); if (isChangeListener) { handlerReplaceListenerRef.set((IHandlerChangeListener) hdl); } if (isDisconnected) { callDisconnect = true; } } if (ConnectionUtils.isDispatcherThread()) { onData(true); }else { onData(false); } // is disconnected if (callDisconnect) { adapter.onDisconnect(this, holder.connection.getTaskQueue(), holder.connection.getExecutor(), false); } } } public IHandler getHandler() { ensureOpen(); if (nativeConnectionHolderRef.get() == null) { return null; } HandlerAdapter handlerAdapter = handlerAdapterRef.get(); if (handlerAdapter == null) { return null; } else { return ((HandlerAdapter) handlerAdapter).getHandler(); } } boolean isDestroyed() { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (holder != null) { return !holder.getConnection().isConnected(); } else { return true; } } public boolean isOpen() { if (!isOpen) { return false; } NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (holder != null) { return holder.getConnection().isOpen(); } else { return false; } } public void close() throws IOException { initiateOnDisconnect(); NativeConnectionHolder holder = nativeConnectionHolderRef.getAndSet(null); if (holder != null) { holder.unregister(); } } void destroy() { initiateOnDisconnect(); NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (holder != null) { try { holder.close(); } catch (Exception e) { // eat and log exception if (LOG.isLoggable(Level.FINE)) { LOG.fine("[" + getId() + "] error occured while destroying pooledConnectionHolder " + nativeConnectionHolderRef.get() + " reason: " + e.toString()); } } } } private void initiateOnDisconnect() { boolean isDispatcherThread = ConnectionUtils.isDispatcherThread(); try { onData(isDispatcherThread); } catch (IOException ignore) { } onDisconnect(isDispatcherThread); } @Override public String toString() { StringBuilder sb = new StringBuilder(); try { sb.append(getId()); if (!isOpen()) { sb.append(" closed"); } NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (holder != null) { sb.append(" (" + holder.getAddress() + ") "); } sb.append(" (proxy "); if (holder == null) { sb.append("closed " + ", countReuse=" + countReuse + ", ageProxyMillis=" + (System.currentTimeMillis() - creationTime) + ", elapsedLastUsageMillis=" + (System.currentTimeMillis() - elapsedLastUsage)); } else { sb.append("received=" + getNumberOfReceivedBytes() + ", sent=" + getNumberOfSendBytes() + ", countReuse=" + countReuse + ", agePhysicalMillis=" + (System.currentTimeMillis() - holder.creationTimeMillis) + ", pooledLifeTimeout=" + holder.getPooledMaxLifeTimeMillis() + ", pooledIdleTimeout=" + holder.getPooledMaxIdleTimeMillis() + ", ageProxyMillis=" + (System.currentTimeMillis() - creationTime) + ", elapsedLastUsageMillis=" + (System.currentTimeMillis() - elapsedLastUsage) + ", elapsedTimeLastSent=" + (System.currentTimeMillis() - holder.getConnection().getLastTimeSendMillis()) + ", elapsedTimeLastReceived=" + (System.currentTimeMillis() - holder.getConnection().getLastTimeReceivedMillis())); } } catch (Exception ignore) { } return sb.toString(); } public String getId() { return id; } private boolean onConnect() { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); HandlerAdapter handlerAdapter = handlerAdapterRef.get(); if ((holder != null) && (handlerAdapter != null)) { try { return handlerAdapter.onConnect(this, holder.connection.getTaskQueue(), holder.connection.getExecutor()); } catch (IOException ioe) { if (LOG.isLoggable(Level.FINE)) { LOG.fine("[" + getId() + "] Error occured by perform onConnect callback on " + handlerAdapter + " " + ioe.toString()); } return false; } } else { return false; } } private boolean onDisconnect(boolean isUnsynchronized) { HandlerAdapter adapter = null; synchronized (disconnectedGuard) { if (isDisconnected) { return true; } else { isDisconnected = true; adapter = handlerAdapterRef.get(); } } NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if ((holder != null) && (adapter != null)) { try { adapter.onDisconnect(this, holder.connection.getTaskQueue(), holder.connection.getExecutor(), isUnsynchronized); } catch (IOException ioe) { if (LOG.isLoggable(Level.FINE)) { LOG.fine("[" + getId() + "] Error occured by perform onDisconnect callback on " + adapter + " " + ioe.toString()); } } } return true; } private boolean onData(boolean isUnsynchroized) throws IOException, MaxReadSizeExceededException { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); HandlerAdapter handlerAdapter = handlerAdapterRef.get(); if ((holder != null) && (handlerAdapter != null)) { return handlerAdapter.onData(this, holder.connection.getTaskQueue(), holder.connection.getExecutor(), false, isUnsynchroized); } else { if (LOG.isLoggable(Level.FINE)) { LOG.fine("[" + getId() + "] onData called even though proxy is closed"); } return true; } } private boolean onConnectionTimeout() throws IOException { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); HandlerAdapter handlerAdapter = handlerAdapterRef.get(); if ((holder != null) && (handlerAdapter != null)) { if (!isConnectionTimeoutOccured.getAndSet(true)) { return handlerAdapter.onConnectionTimeout(this, holder.connection.getTaskQueue(), holder.connection.getExecutor()); } else { return true; } } else { if (LOG.isLoggable(Level.FINE)) { LOG.fine("[" + getId() + "] onConnectionTimeout called even though proxy is closed"); } return true; } } private boolean onIdleTimeout() throws IOException { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); HandlerAdapter handlerAdapter = handlerAdapterRef.get(); if ((holder != null) && (handlerAdapter != null)) { if (!isIdleTimeoutOccured.getAndSet(true)) { return handlerAdapter.onIdleTimeout(this, holder.connection.getTaskQueue(), holder.connection.getExecutor()); } else { return true; } } else { if (LOG.isLoggable(Level.FINE)) { LOG.fine("[" + getId() + "] onIdletimeout called even though proxy is closed"); } return true; } } public boolean isServerSide() { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (isOpen && (holder != null)) { return holder.getConnection().isServerSide(); } else { throw newClosedChannelRuntimeException(); } } public Executor getWorkerpool() { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (holder != null) { return holder.getConnection().getWorkerpool(); } else { return NonBlockingConnection.getDefaultWorkerpool(); } } public void setWorkerpool(Executor workerpool) { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (isOpen && (holder != null)) { holder.getConnection().setWorkerpool(workerpool); } } public void setAttachment(Object obj) { this.attachment = obj; } public Object getAttachment() { return attachment; } public void setAutoflush(boolean autoflush) { isAutoflush = autoflush; } public boolean isAutoflush() { return isAutoflush; } public void setEncoding(String defaultEncoding) { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (isOpen && (holder != null)) { holder.getConnection().setEncoding(defaultEncoding); } } public String getEncoding() { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (isOpen && (holder != null)) { return holder.getConnection().getEncoding(); } else { return IConnection.INITIAL_DEFAULT_ENCODING; } } public void setFlushmode(FlushMode flushMode) { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (isOpen && (holder != null)) { holder.getConnection().setFlushmode(flushMode); } } public FlushMode getFlushmode() { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (isOpen && (holder != null)) { return holder.getConnection().getFlushmode(); } else { return IConnection.DEFAULT_FLUSH_MODE; } } public void setOption(String name, Object value) throws IOException { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (isOpen && (holder != null)) { holder.getConnection().setOption(name, value); } } public Object getOption(String name) throws IOException { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (isOpen && (holder != null)) { try { return holder.getConnection().getOption(name); } catch (IOException ioe) { destroy(); throw ioe; } } else { throw newClosedChannelRuntimeException(); } } public long getNumberOfReceivedBytes() { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if ((holder != null)) { return holder.getConnection().getNumberOfReceivedBytes() - initialReceivedBytes; } else { throw newClosedChannelRuntimeException(); } } public long getNumberOfSendBytes() { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if ((holder != null)) { return holder.getConnection().getNumberOfSendBytes() - initialSendBytes; } else { throw newClosedChannelRuntimeException(); } } @SuppressWarnings("unchecked") public Map getOptions() { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (isOpen && (holder != null)) { return holder.getConnection().getOptions(); } else { throw newClosedChannelRuntimeException(); } } public void setWriteTransferRate(int bytesPerSecond) throws ClosedChannelException, IOException { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (isOpen && (holder != null)) { try { holder.getConnection().setWriteTransferRate(bytesPerSecond); } catch (IOException ioe) { destroy(); throw ioe; } } } public int getWriteTransferRate() throws ClosedChannelException, IOException { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (isOpen && (holder != null)) { try { return holder.getConnection().getWriteTransferRate(); } catch (IOException ioe) { destroy(); throw ioe; } } else { return INonBlockingConnection.UNLIMITED; } } public int getMaxReadBufferThreshold() { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (isOpen && (holder != null)) { return holder.getConnection().getMaxReadBufferThreshold(); } else { return Integer.MAX_VALUE; } } public void setMaxReadBufferThreshold(int size) { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (isOpen && (holder != null)) { holder.getConnection().setMaxReadBufferThreshold(size); } } public void setConnectionTimeoutMillis(long timeoutMillis) { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (isOpen && (holder != null)) { holder.getConnection().setConnectionTimeoutMillis(timeoutMillis); } } public long getConnectionTimeoutMillis() { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (isOpen && (holder != null)) { return holder.getConnection().getConnectionTimeoutMillis(); } else { return Long.MAX_VALUE; } } public void setIdleTimeoutMillis(long timeoutInMillis) { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (isOpen && (holder != null)) { holder.getConnection().setIdleTimeoutMillis(timeoutInMillis); isIdleTimeoutOccured.set(false); } else { throw newClosedChannelRuntimeException(); } } public long getIdleTimeoutMillis() { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (isOpen && (holder != null)) { return holder.getConnection().getIdleTimeoutMillis(); } else { return Long.MAX_VALUE; } } public long getRemainingMillisToConnectionTimeout() { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (isOpen && (holder != null)) { return holder.getConnection().getConnectionTimeoutMillis(); } else { return Long.MAX_VALUE; } } public long getRemainingMillisToIdleTimeout() { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (isOpen && (holder != null)) { return holder.getConnection().getRemainingMillisToIdleTimeout(); } else { return Long.MAX_VALUE; } } public boolean isSecure() { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (isOpen && (holder != null)) { return holder.getConnection().isSecure(); } else { throw newClosedChannelRuntimeException(); } } public void activateSecuredMode() throws IOException { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (isOpen && (holder != null)) { try { holder.getConnection().activateSecuredMode(); } catch (IOException ioe) { destroy(); throw ioe; } } } public void deactivateSecuredMode() throws IOException { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (isOpen && (holder != null)) { try { holder.getConnection().deactivateSecuredMode(); } catch (IOException ioe) { destroy(); throw ioe; } } } public boolean isSecuredModeActivateable() { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (isOpen && (holder != null)) { return holder.getConnection().isSecuredModeActivateable(); } else { return false; } } public void suspendReceiving() throws IOException { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (isOpen && (holder != null)) { try { holder.getConnection().suspendReceiving(); } catch (IOException ioe) { destroy(); throw ioe; } } } public boolean isReceivingSuspended() { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (isOpen && (holder != null)) { return holder.getConnection().isReceivingSuspended(); } else { return false; } } public void resumeReceiving() throws IOException { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (isOpen && (holder != null)) { try { holder.getConnection().resumeReceiving(); } catch (IOException ioe) { destroy(); throw ioe; } } } public InetAddress getLocalAddress() { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (holder != null) { return holder.getConnection().getLocalAddress(); } else { throw newClosedChannelRuntimeException(); } } public int getLocalPort() { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (holder != null) { return holder.getConnection().getLocalPort(); } else { throw newClosedChannelRuntimeException(); } } public InetAddress getRemoteAddress() { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (holder != null) { return holder.getConnection().getRemoteAddress(); } else { throw newClosedChannelRuntimeException(); } } public int getRemotePort() { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (holder != null) { return holder.getConnection().getRemotePort(); } else { throw newClosedChannelRuntimeException(); } } public void write(ByteBuffer[] buffers, IWriteCompletionHandler writeCompletionHandler) throws IOException { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (isOpen && (holder != null)) { try { holder.getConnection().write(buffers, writeCompletionHandler); if (isAutoflush) { flush(); } } catch (IOException ioe) { if (LOG.isLoggable(Level.FINE)) { LOG.fine("error occured by writing " + DataConverter.toString(buffers) + " deregistering "); } destroy(); throw ioe; } } else { throw newClosedChannelException(); } } public long write(ByteBuffer[] buffers) throws IOException, BufferOverflowException { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (isOpen && (holder != null)) { try { long written = holder.getConnection().write(buffers); if (isAutoflush) { flush(); } return written; } catch (IOException ioe) { destroy(); throw ioe; } } else { throw newClosedChannelException(); } } public int write(ByteBuffer buffer) throws IOException, BufferOverflowException { return (int) write(new ByteBuffer[] { buffer }); } public void write(ByteBuffer buffer, IWriteCompletionHandler writeCompletionHandler) throws IOException { write(new ByteBuffer[] { buffer }, writeCompletionHandler); } public long write(ByteBuffer[] srcs, int offset, int length) throws IOException { return write(DataConverter.toByteBuffers(srcs, offset, length)); } public void write(ByteBuffer[] srcs, int offset, int length, IWriteCompletionHandler writeCompletionHandler) throws IOException { write(DataConverter.toByteBuffers(srcs, offset, length), writeCompletionHandler); } public long write(List buffers) throws IOException, BufferOverflowException { return write(buffers.toArray(new ByteBuffer[buffers.size()])); } public void write(List buffers, IWriteCompletionHandler writeCompletionHandler) throws IOException { write(buffers.toArray(new ByteBuffer[buffers.size()]), writeCompletionHandler); } public void write(byte[] bytes, IWriteCompletionHandler writeCompletionHandler) throws IOException { write(DataConverter.toByteBuffer(bytes), writeCompletionHandler); } public int write(byte[] bytes, int offset, int length) throws IOException, BufferOverflowException { return write(DataConverter.toByteBuffer(bytes, offset, length)); } public void write(byte[] bytes, int offset, int length, IWriteCompletionHandler writeCompletionHandler) throws IOException { write(DataConverter.toByteBuffer(bytes, offset, length), writeCompletionHandler); } public int write(byte b) throws IOException, BufferOverflowException { return write(DataConverter.toByteBuffer(b)); } public int write(byte... bytes) throws IOException, BufferOverflowException { return write(DataConverter.toByteBuffer(bytes)); } public int write(long l) throws IOException, BufferOverflowException { return write(DataConverter.toByteBuffer(l)); } public int write(double d) throws IOException, BufferOverflowException { return write(DataConverter.toByteBuffer(d)); } public int write(int i) throws IOException, BufferOverflowException { return write(DataConverter.toByteBuffer(i)); } public int write(short s) throws IOException, BufferOverflowException { return write(DataConverter.toByteBuffer(s)); } public int write(String message) throws IOException, BufferOverflowException { return write(DataConverter.toByteBuffer(message, getEncoding())); } public int write(String message, String encoding) throws IOException, BufferOverflowException { return write(DataConverter.toByteBuffer(message, encoding)); } public void write(String message, String encoding, IWriteCompletionHandler writeCompletionHandler) throws IOException { write(DataConverter.toByteBuffer(message, encoding), writeCompletionHandler); } public void flush() throws ClosedChannelException, IOException, SocketTimeoutException { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (isOpen && (holder != null)) { try { holder.getConnection().flush(); } catch (IOException ioe) { destroy(); throw ioe; } } else { throw newClosedChannelException(); } } public long transferFrom(FileChannel fileChannel) throws IOException, BufferOverflowException { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (isOpen && (holder != null)) { try { if (getFlushmode() == FlushMode.SYNC) { if (LOG.isLoggable(Level.FINE)) { LOG.fine("tranfering file by using MappedByteBuffer (MAX_MAP_SIZE=" + AbstractNonBlockingStream.TRANSFER_BYTE_BUFFER_MAX_MAP_SIZE + ")"); } final long size = fileChannel.size(); long remaining = size; long offset = 0; long length = 0; do { if (remaining > AbstractNonBlockingStream.TRANSFER_BYTE_BUFFER_MAX_MAP_SIZE) { length = AbstractNonBlockingStream.TRANSFER_BYTE_BUFFER_MAX_MAP_SIZE; } else { length = remaining; } MappedByteBuffer buffer = fileChannel.map(MapMode.READ_ONLY, offset, length); long written = write(buffer); offset += written; remaining -= written; } while (remaining > 0); return size; } else { return transferFrom((ReadableByteChannel) fileChannel); } } catch (IOException ioe) { destroy(); throw ioe; } } else { throw newClosedChannelException(); } } public long transferFrom(ReadableByteChannel source) throws IOException, BufferOverflowException { return transferFrom(source, AbstractNonBlockingStream.TRANSFER_BYTE_BUFFER_MAX_MAP_SIZE); } public long transferFrom(ReadableByteChannel source, int chunkSize) throws IOException, BufferOverflowException { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (isOpen && (holder != null)) { try { long transfered = 0; int read = 0; do { ByteBuffer transferBuffer = ByteBuffer.allocate(chunkSize); read = source.read(transferBuffer); if (read > 0) { if (transferBuffer.remaining() == 0) { transferBuffer.flip(); write(transferBuffer); } else { transferBuffer.flip(); write(transferBuffer.slice()); } transfered += read; } } while (read > 0); return transfered; } catch (IOException ioe) { destroy(); throw ioe; } } else { throw newClosedChannelException(); } } public int getPendingWriteDataSize() { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (isOpen && (holder != null)) { return holder.getConnection().getPendingWriteDataSize(); } else { throw newClosedChannelRuntimeException(); } } public void markWritePosition() { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (isOpen && (holder != null)) { holder.getConnection().markWritePosition(); } else { throw newClosedChannelRuntimeException(); } } public void removeWriteMark() { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (isOpen && (holder != null)) { holder.getConnection().removeWriteMark(); } } public boolean resetToWriteMark() { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (isOpen && (holder != null)) { return holder.getConnection().resetToWriteMark(); } else { throw newClosedChannelRuntimeException(); } } public void markReadPosition() { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (isOpen && (holder != null)) { holder.getConnection().markReadPosition(); } else { throw newClosedChannelRuntimeException(); } } public void removeReadMark() { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (isOpen && (holder != null)) { holder.getConnection().removeReadMark(); } } public boolean resetToReadMark() { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (isOpen && (holder != null)) { return holder.getConnection().resetToReadMark(); } else { throw newClosedChannelRuntimeException(); } } public int available() throws IOException { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (holder != null) { return holder.getConnection().available(); } else { return -1; } } public int getReadBufferVersion() throws IOException { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (holder != null) { return holder.getConnection().getReadBufferVersion(); } else { return -1; } } public int indexOf(String str) throws IOException { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (holder != null) { try { return holder.getConnection().indexOf(str); } catch (IOException ioe) { destroy(); throw ioe; } } else { return -1; } } public int indexOf(String str, String encoding) throws IOException { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (holder != null) { try { return holder.getConnection().indexOf(str, encoding); } catch (IOException ioe) { destroy(); throw ioe; } } else { return -1; } } public void unread(ByteBuffer[] buffers) throws IOException { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (isOpen && (holder != null)) { try { holder.getConnection().unread(buffers); } catch (IOException ioe) { destroy(); throw ioe; } } else { throw newClosedChannelRuntimeException(); } } public void unread(byte[] bytes) throws IOException { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (isOpen && (holder != null)) { try { holder.getConnection().unread(bytes); } catch (IOException ioe) { destroy(); throw ioe; } } else { throw newClosedChannelRuntimeException(); } } public void unread(ByteBuffer buffer) throws IOException { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (isOpen && (holder != null)) { try { holder.getConnection().unread(buffer); } catch (IOException ioe) { destroy(); throw ioe; } } else { throw newClosedChannelRuntimeException(); } } public void unread(String text) throws IOException { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (isOpen && (holder != null)) { try { holder.getConnection().unread(text); } catch (IOException ioe) { destroy(); throw ioe; } } else { throw newClosedChannelRuntimeException(); } } public int read(ByteBuffer buffer) throws IOException { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (holder != null) { try { return holder.getConnection().read(buffer); } catch (IOException ioe) { destroy(); throw ioe; } } else { return -1; } } public byte readByte() throws IOException, BufferUnderflowException { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (holder != null) { try { return holder.getConnection().readByte(); } catch (IOException ioe) { destroy(); throw ioe; } } else { throw newClosedChannelException(); } } public ByteBuffer[] readByteBufferByDelimiter(String delimiter) throws IOException, BufferUnderflowException { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (holder != null) { try { return holder.getConnection().readByteBufferByDelimiter(delimiter); } catch (IOException ioe) { destroy(); throw ioe; } } else { throw newClosedChannelException(); } } public ByteBuffer[] readByteBufferByDelimiter(String delimiter, int maxLength) throws IOException, BufferUnderflowException, MaxReadSizeExceededException { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (holder != null) { try { return holder.getConnection().readByteBufferByDelimiter(delimiter, maxLength); } catch (IOException ioe) { destroy(); throw ioe; } } else { throw newClosedChannelException(); } } public ByteBuffer[] readByteBufferByDelimiter(String delimiter, String encoding) throws IOException, BufferUnderflowException { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (holder != null) { try { return holder.getConnection().readByteBufferByDelimiter(delimiter, encoding); } catch (IOException ioe) { destroy(); throw ioe; } } else { throw newClosedChannelException(); } } public ByteBuffer[] readByteBufferByDelimiter(String delimiter, String encoding, int maxLength) throws IOException, BufferUnderflowException, MaxReadSizeExceededException { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (holder != null) { try { return holder.getConnection().readByteBufferByDelimiter(delimiter, encoding, maxLength); } catch (IOException ioe) { destroy(); throw ioe; } } else { throw newClosedChannelException(); } } public ByteBuffer[] readByteBufferByLength(int length) throws IOException, BufferUnderflowException { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (holder != null) { try { return holder.getConnection().readByteBufferByLength(length); } catch (IOException ioe) { destroy(); throw ioe; } } else { throw newClosedChannelException(); } } public byte[] readBytesByDelimiter(String delimiter) throws IOException, BufferUnderflowException { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (holder != null) { try { return holder.getConnection().readBytesByDelimiter(delimiter); } catch (IOException ioe) { destroy(); throw ioe; } } else { throw newClosedChannelException(); } } public byte[] readBytesByDelimiter(String delimiter, int maxLength) throws IOException, BufferUnderflowException, MaxReadSizeExceededException { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (holder != null) { try { return holder.getConnection().readBytesByDelimiter(delimiter, maxLength); } catch (IOException ioe) { destroy(); throw ioe; } } else { throw newClosedChannelException(); } } public byte[] readBytesByDelimiter(String delimiter, String encoding) throws IOException, BufferUnderflowException { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (holder != null) { try { return holder.getConnection().readBytesByDelimiter(delimiter, encoding); } catch (IOException ioe) { destroy(); throw ioe; } } else { throw newClosedChannelException(); } } public byte[] readBytesByDelimiter(String delimiter, String encoding, int maxLength) throws IOException, BufferUnderflowException, MaxReadSizeExceededException { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (holder != null) { try { return holder.getConnection().readBytesByDelimiter(delimiter, encoding, maxLength); } catch (IOException ioe) { destroy(); throw ioe; } } else { throw newClosedChannelException(); } } public byte[] readBytesByLength(int length) throws IOException, BufferUnderflowException { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (holder != null) { try { return holder.getConnection().readBytesByLength(length); } catch (IOException ioe) { destroy(); throw ioe; } } else { throw newClosedChannelException(); } } public double readDouble() throws IOException, BufferUnderflowException { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (holder != null) { try { return holder.getConnection().readDouble(); } catch (IOException ioe) { destroy(); throw ioe; } } else { throw newClosedChannelException(); } } public int readInt() throws IOException, BufferUnderflowException { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (holder != null) { try { return holder.getConnection().readInt(); } catch (IOException ioe) { destroy(); throw ioe; } } else { throw newClosedChannelException(); } } public long readLong() throws IOException, BufferUnderflowException { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (holder != null) { try { return holder.getConnection().readLong(); } catch (IOException ioe) { destroy(); throw ioe; } } else { throw newClosedChannelException(); } } public short readShort() throws IOException, BufferUnderflowException { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (holder != null) { try { return holder.getConnection().readShort(); } catch (IOException ioe) { destroy(); throw ioe; } } else { throw newClosedChannelException(); } } public String readStringByDelimiter(String delimiter) throws IOException, BufferUnderflowException, UnsupportedEncodingException { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (holder != null) { try { return holder.getConnection().readStringByDelimiter(delimiter); } catch (IOException ioe) { destroy(); throw ioe; } } else { throw newClosedChannelException(); } } public String readStringByDelimiter(String delimiter, int maxLength) throws IOException, BufferUnderflowException, UnsupportedEncodingException, MaxReadSizeExceededException { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (holder != null) { try { return holder.getConnection().readStringByDelimiter(delimiter, maxLength); } catch (IOException ioe) { destroy(); throw ioe; } } else { throw newClosedChannelException(); } } public String readStringByDelimiter(String delimiter, String encoding) throws IOException, BufferUnderflowException, UnsupportedEncodingException, MaxReadSizeExceededException { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (holder != null) { try { return holder.getConnection().readStringByDelimiter(delimiter, encoding); } catch (IOException ioe) { destroy(); throw ioe; } } else { throw newClosedChannelException(); } } public String readStringByDelimiter(String delimiter, String encoding, int maxLength) throws IOException, BufferUnderflowException, UnsupportedEncodingException, MaxReadSizeExceededException { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (holder != null) { try { return holder.getConnection().readStringByDelimiter(delimiter, encoding, maxLength); } catch (IOException ioe) { destroy(); throw ioe; } } else { throw newClosedChannelException(); } } public String readStringByLength(int length) throws IOException, BufferUnderflowException, UnsupportedEncodingException { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (holder != null) { try { return holder.getConnection().readStringByLength(length); } catch (IOException ioe) { destroy(); throw ioe; } } else { throw newClosedChannelException(); } } public String readStringByLength(int length, String encoding) throws IOException, BufferUnderflowException, UnsupportedEncodingException { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (holder != null) { try { return holder.getConnection().readStringByLength(length, encoding); } catch (IOException ioe) { destroy(); throw ioe; } } else { throw newClosedChannelException(); } } public long transferTo(WritableByteChannel target, int length) throws IOException, BufferUnderflowException { NativeConnectionHolder holder = nativeConnectionHolderRef.get(); if (holder != null) { try { return holder.getConnection().transferTo(target, length); } catch (IOException ioe) { destroy(); throw ioe; } } else { throw newClosedChannelException(); } } private ExtendedClosedChannelException newClosedChannelException() { return new ExtendedClosedChannelException("channel " + getId() + " is already closed"); } private RuntimeException newClosedChannelRuntimeException() { return new RuntimeException("channel " + getId() + " is already closed"); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy