package com.app.mvc.http;
import com.app.mvc.config.GlobalConfig;
import com.app.mvc.config.GlobalConfigKey;
import com.app.mvc.http.ext.AuthSSLInitializationError;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
import org.apache.commons.httpclient.HttpMethodBase;
import java.util.concurrent.Callable;
import java.util.concurrent.Executors;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Strings.isNullOrEmpty;
/**
* 支持异步操作的http client
* Created by jimin on 16/03/10.
*/
class AsyncHttpClient extends SyncHttpClient {
static ListeningExecutorService threadPool;
static { //init the thread pool
Integer threadMax = GlobalConfig.getIntValue(GlobalConfigKey.HTTP_MAX_THREAD, 20);
if (threadMax == null || threadMax == 0) {
threadPool = MoreExecutors.listeningDecorator(Executors.newCachedThreadPool());
} else {
threadPool = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(threadMax));
}
}
@Override
public ResponseWrapper get(String uri) {
throw new UnsupportedOperationException("异步客户端不支持调用同步方法,请调用 asyncGet");
}
@Override
public ResponseWrapper post(String uri, String content) {
throw new UnsupportedOperationException("异步客户端不支持调用同步方法,请调用 asyncPost");
}
@Override
public ResponseWrapper post(String uri) {
throw new UnsupportedOperationException("异步客户端不支持调用同步方法,请调用 asyncPost");
}
@Override
public ListenableFuture<ResponseWrapper> asyncGet(final String uri) {
checkArgument(!isNullOrEmpty(uri), "uri不能为null或空");
ListenableFuture<ResponseWrapper> future = threadPool.submit(new Callable<ResponseWrapper>() {
@Override
public ResponseWrapper call() throws Exception {
return doMethod(buildGetMethod(uri));
}
});
Futures.addCallback(future, callBack);
return future;
}
@Override
public ListenableFuture<ResponseWrapper> asyncPost(final String uri, final String content) {
checkArgument(!isNullOrEmpty(uri), "uri不能为null或空");
checkArgument(!isNullOrEmpty(content), "content不能为null或空");
ListenableFuture<ResponseWrapper> future = threadPool.submit(new Callable<ResponseWrapper>() {
@Override
public ResponseWrapper call() throws Exception {
return doMethod(buildPostMethod(uri, content));
}
});
Futures.addCallback(future, callBack);
return future;
}
@Override
public ListenableFuture<ResponseWrapper> asyncPost(final String uri) {
checkArgument(!isNullOrEmpty(uri), "uri不能为null或空");
ListenableFuture<ResponseWrapper> future = threadPool.submit(new Callable<ResponseWrapper>() {
@Override
public ResponseWrapper call() throws Exception {
return doMethod(buildPostMethod(uri, null));
}
});
Futures.addCallback(future, callBack);
return future;
}
/**
* 实际上,我们的异步方式不过使采用多线程进行异步操作,而不是基于异步套接子的操作。
* 因为我们暂时不需要引入HttpAsyncClient,这种多线程的形式已经能够满足大部分的需要
* 因为大部分场景,我们都是不希望影响主流程。并且后期切换也非常的容易
*
* @param method HttpMethodBase
* @return ResponseWrapper
*/
private ResponseWrapper doMethod(HttpMethodBase method) {
try {
/** we blocked here */
httpClient.executeMethod(method);
return ResponseWrapper.of(method);
} catch (Throwable e) { //not only exp
if (e instanceof AuthSSLInitializationError) {
callBack.onAuthority((AuthSSLInitializationError) e);
} else {
throw new RuntimeException(e);
}
} finally {
method.releaseConnection();
}
return null;
}
}