| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| */ |
| package org.apache.ahc; |
| |
| import java.net.InetSocketAddress; |
| import java.util.Queue; |
| import java.util.concurrent.ConcurrentHashMap; |
| import java.util.concurrent.ConcurrentLinkedQueue; |
| import java.util.concurrent.ConcurrentMap; |
| |
| import org.apache.ahc.codec.HttpRequestMessage; |
| import org.apache.mina.core.session.IoSession; |
| |
| /** |
| * Facilitates support for connection pooling by storing IoSession instances |
| * that have keepAlive enabled. Connection pooling is based on the |
| * IoSession's remote host and port. |
| * |
| * <p>This class is thread safe. |
| */ |
| public final class ConnectionPool { |
| private final ConcurrentMap<String,Queue<IoSession>> pooledSessions = |
| new ConcurrentHashMap<String,Queue<IoSession>>(); |
| |
| public ConnectionPool() {} |
| |
| /** |
| * Returns an IoSession that is connected and considered usable. Note that |
| * this is still on a best-effort basis, and there is no guarantee that the |
| * connection can be used without errors, although it should be usually |
| * safe to use it. |
| * |
| * @param msg the message for which to look up an active session. |
| * @throws IllegalArgumentException if a null request message was passed in. |
| * @return an active IoSession, or null if none are found. |
| */ |
| public IoSession getActiveSession(HttpRequestMessage msg) { |
| if (msg == null) { |
| throw new IllegalArgumentException("null request was passed in"); |
| } |
| |
| Queue<IoSession> queue = pooledSessions.get(getKey(msg)); |
| if (queue == null) { |
| return null; |
| } |
| |
| IoSession pooled = null; |
| while ((pooled = queue.poll()) != null) { |
| // see if the session is usable |
| if (pooled.isConnected() && !pooled.isClosing()) { |
| return pooled; |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Places the given session in the pool of available connections based on the session's remote host and port. |
| * |
| * @param session IoSession to pool |
| * @throws IllegalArgumentException if a null session was passed in. |
| */ |
| void poolConnection(IoSession session) { |
| if (session == null) { |
| throw new IllegalArgumentException("null session was passed in"); |
| } |
| |
| String key = getKey((InetSocketAddress)session.getRemoteAddress()); |
| Queue<IoSession> newQueue = new ConcurrentLinkedQueue<IoSession>(); |
| Queue<IoSession> queue = pooledSessions.putIfAbsent(key, newQueue); |
| if (queue == null) { |
| // the value was previously empty |
| queue = newQueue; |
| } |
| // add it to the queue |
| queue.offer(session); |
| } |
| |
| /** |
| * Removes the given session from the pool if it is in the pool. |
| * |
| * @param session IoSession to remove from the pool |
| * @throws IllegalArgumentException if a null session was passed in |
| */ |
| void removeSession(IoSession session) { |
| if (session == null) { |
| throw new IllegalArgumentException("null session was passed in"); |
| } |
| |
| String key = getKey((InetSocketAddress)session.getRemoteAddress()); |
| Queue<IoSession> queue = pooledSessions.get(key); |
| if (queue != null) { |
| queue.remove(session); |
| } |
| } |
| |
| /** |
| * Generate a request key from an HTTP request message. |
| * |
| * @param msg The request message we need a key from. |
| * |
| * @return A String key instance for this request. |
| */ |
| private String getKey(HttpRequestMessage msg) { |
| return getKey(msg.getHost(), msg.getPort()); |
| } |
| |
| /** |
| * Generate a session key from an InetSocketAddress |
| * |
| * @param remote The endpoint address of the connection. |
| * |
| * @return A string key for this endpoint. |
| */ |
| private String getKey(InetSocketAddress remote) { |
| return getKey(remote.getHostName(), remote.getPort()); |
| } |
| |
| /** |
| * The key is of the form "host:port". |
| */ |
| private String getKey(String host, int port) { |
| return new StringBuilder(host).append(':').append(port).toString(); |
| } |
| } |