org.siddhiesb.transport.passthru.connections.TargetConnections.java Source code

Java tutorial

Introduction

Here is the source code for org.siddhiesb.transport.passthru.connections.TargetConnections.java

Source

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

package org.siddhiesb.transport.passthru.connections;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpHost;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.nio.NHttpClientConnection;
import org.apache.http.nio.reactor.ConnectingIOReactor;
import org.siddhiesb.transport.passthru.ConnectCallback;
import org.siddhiesb.transport.passthru.PassThroughConstants;
import org.siddhiesb.transport.passthru.TargetContext;
import org.siddhiesb.transport.passthru.config.TargetConfiguration;
import org.siddhiesb.transport.passthru.connections.*;

import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.net.InetSocketAddress;

/**
 * Manages the connection from transport to the back end servers. It keeps track of the
 * connections for host:port pair. 
 */
public class TargetConnections {
    private static final Log log = LogFactory.getLog(TargetConnections.class);

    /** map to hold the ConnectionPools. The key is host:port */
    private final Map<HttpRoute, org.siddhiesb.transport.passthru.connections.HostConnections> poolMap = new ConcurrentHashMap<HttpRoute, org.siddhiesb.transport.passthru.connections.HostConnections>();

    /** max connections per host:port pair. At the moment all the host:ports can
     * have the same max */
    private int maxConnections;

    /** io-reactor to use for creating connections */
    private ConnectingIOReactor ioReactor;

    /** callback invoked when a connection is made */
    private ConnectCallback callback = null;

    /**
     * Create a TargetConnections with the given IO-Reactor
     *
     * @param ioReactor the IO-Reactor
     * @param targetConfiguration the configuration of the sender
     * @param callback the callback
     */
    public TargetConnections(ConnectingIOReactor ioReactor, TargetConfiguration targetConfiguration,
            ConnectCallback callback) {

        this.maxConnections = targetConfiguration.getMaxConnections();
        this.ioReactor = ioReactor;
        this.callback = callback;
    }

    /**
     * Return a connection to the host:port pair. If a connection is not available
     * return <code>null</code>. If the particular host:port allows to create more connections
     * this method will try to connect asynchronously. If the connection is successful it will
     * be notified in a separate thread.
     *
     * @param host host
     * @param port port
     * @return Either returns a connection if already available or returns null and notifies
     *         the delivery agent when the connection is available
     */
    public NHttpClientConnection getConnection(HttpRoute route) {
        if (log.isDebugEnabled()) {
            log.debug("Trying to get a connection " + route);
        }

        org.siddhiesb.transport.passthru.connections.HostConnections pool = getConnectionPool(route);

        // trying to get an existing connection
        NHttpClientConnection connection = pool.getConnection();
        if (connection == null) {
            if (pool.canHaveMoreConnections()) {
                HttpHost host = route.getProxyHost() != null ? route.getProxyHost() : route.getTargetHost();
                ioReactor.connect(new InetSocketAddress(host.getHostName(), host.getPort()), null, pool, callback);
            } else {
                log.warn("Connection pool reached maximum allowed connections for route " + route
                        + ". Target server may have become slow");
            }
        }

        return connection;
    }

    /**
     * This connection is no longer valid. So we need to shutdownConnection connection.
     *
     * @param conn connection to shutdownConnection
     */
    public void shutdownConnection(NHttpClientConnection conn) {
        org.siddhiesb.transport.passthru.connections.HostConnections pool = (org.siddhiesb.transport.passthru.connections.HostConnections) conn
                .getContext().getAttribute(PassThroughConstants.CONNECTION_POOL);

        TargetContext.get(conn).reset();

        if (pool != null) {
            pool.forget(conn);
        } else {
            // we shouldn't get here
            log.fatal("Connection without a pool. Something wrong. Need to fix.");
        }

        try {
            conn.shutdown();
        } catch (IOException ignored) {
        }
    }

    /**
     * Release an active connection to the pool
     *
     * @param conn connection to be released
     */
    public void releaseConnection(NHttpClientConnection conn) {
        org.siddhiesb.transport.passthru.connections.HostConnections pool = (org.siddhiesb.transport.passthru.connections.HostConnections) conn
                .getContext().getAttribute(PassThroughConstants.CONNECTION_POOL);

        TargetContext.get(conn).reset();

        if (pool != null) {
            pool.release(conn);
        } else {
            // we shouldn't get here
            log.fatal("Connection without a pool. Something wrong. Need to fix.");
        }
    }

    /**
     * This method is called when a new connection is made.
     *
     * @param conn connection to the target server     
     */
    public void addConnection(NHttpClientConnection conn) {
        org.siddhiesb.transport.passthru.connections.HostConnections pool = (org.siddhiesb.transport.passthru.connections.HostConnections) conn
                .getContext().getAttribute(PassThroughConstants.CONNECTION_POOL);
        if (pool != null) {
            pool.addConnection(conn);
        } else {
            // we shouldn't get here
            log.fatal("Connection without a pool. Something wrong. Need to fix.");
        }
    }

    private org.siddhiesb.transport.passthru.connections.HostConnections getConnectionPool(HttpRoute route) {
        // see weather a pool already exists for this host:port
        org.siddhiesb.transport.passthru.connections.HostConnections pool = poolMap.get(route);
        synchronized (poolMap) {
            if (pool == null) {
                pool = new org.siddhiesb.transport.passthru.connections.HostConnections(route, maxConnections);
                poolMap.put(route, pool);
            }
        }

        return pool;
    }

}