package com.mossle.core.http;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HttpConnectionPool implements Runnable {
private static Logger logger = LoggerFactory
.getLogger(HttpConnectionPool.class);
public static final int TEN_SECOND = 10000;
private List<HttpConnectionInfo> activeHttpConnectionInfos = new ArrayList<HttpConnectionInfo>();
private List<HttpConnectionInfo> suspendedHttpConnectionInfos = new ArrayList<HttpConnectionInfo>();
private String urls;
private AtomicInteger index = new AtomicInteger(0);
private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
private Thread thread;
private boolean running;
public void init() {
if (urls == null) {
throw new IllegalArgumentException("urls cannot be null");
}
if (urls.trim().length() == 0) {
throw new IllegalArgumentException("urls cannot be empty");
}
for (String url : urls.split(",")) {
HttpConnectionInfo httpConnectionInfo = new HttpConnectionInfo(url);
activeHttpConnectionInfos.add(httpConnectionInfo);
}
running = true;
thread = new Thread(this);
thread.start();
}
public void destroy() {
running = false;
thread = null;
}
public String process(String method, Map<String, String> queryParams,
Map<String, String> formParams, Map<String, String> headParams) {
boolean success = false;
HttpConnectionResult httpConnectionResult = null;
while (!success) {
HttpConnectionInfo httpConnectionInfo = this
.tryToGetHttpConnectionInfo();
httpConnectionResult = httpConnectionInfo.process(method,
queryParams, formParams, headParams);
success = httpConnectionResult.isSuccess();
if (!success) {
this.suspend(httpConnectionInfo);
}
}
return httpConnectionResult.getContent();
}
private HttpConnectionInfo tryToGetHttpConnectionInfo() {
readWriteLock.readLock().lock();
try {
if (activeHttpConnectionInfos.isEmpty()) {
logger.error("suspended HttpConnectionInfos size is {}",
suspendedHttpConnectionInfos.size());
throw new IllegalStateException(
"active HttpConnectionInfos is empty");
}
int temperaryIndex = index.incrementAndGet()
% activeHttpConnectionInfos.size();
return activeHttpConnectionInfos.get(temperaryIndex);
} finally {
readWriteLock.readLock().unlock();
}
}
private void suspend(HttpConnectionInfo httpConnectionInfo) {
readWriteLock.writeLock().lock();
try {
logger.info("suspend {}", httpConnectionInfo.getUrl());
activeHttpConnectionInfos.remove(httpConnectionInfo);
suspendedHttpConnectionInfos.add(httpConnectionInfo);
} finally {
readWriteLock.writeLock().unlock();
}
}
private void active(HttpConnectionInfo httpConnectionInfo) {
readWriteLock.writeLock().lock();
try {
logger.info("active {}", httpConnectionInfo.getUrl());
activeHttpConnectionInfos.add(httpConnectionInfo);
suspendedHttpConnectionInfos.remove(httpConnectionInfo);
} finally {
readWriteLock.writeLock().unlock();
}
}
public void run() {
while (running) {
try {
Thread.sleep(TEN_SECOND);
} catch (InterruptedException ex) {
logger.info(ex.getMessage(), ex);
}
List<HttpConnectionInfo> checkedHttpConnectionInfos = new ArrayList(
suspendedHttpConnectionInfos);
logger.debug("suspended : {}", checkedHttpConnectionInfos.size());
for (HttpConnectionInfo httpConnectionInfo : checkedHttpConnectionInfos) {
logger.debug("check : {}", httpConnectionInfo.getUrl());
if (httpConnectionInfo.check()) {
active(httpConnectionInfo);
} else {
logger.info("{} still broken", httpConnectionInfo.getUrl());
}
}
}
}
public void setUrls(String urls) {
this.urls = urls;
}
public List<HttpConnectionInfo> getActiveHttpConnectionInfos() {
return activeHttpConnectionInfos;
}
public List<HttpConnectionInfo> getSuspendedHttpConnectionInfos() {
return suspendedHttpConnectionInfos;
}
}