/*
* Copyright 2016 Axibase Corporation or its affiliates. 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.
* A copy of the License is located at
*
* https://www.axibase.com/atsd/axibase-apache-2.0.pdf
*
* or in the "license" file accompanying this file. This file 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 com.axibase.tsd.client;
import com.axibase.tsd.model.system.ClientConfiguration;
import com.axibase.tsd.network.PlainCommand;
import com.axibase.tsd.query.QueryPart;
import org.apache.commons.pool2.BasePooledObjectFactory;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import java.io.InputStream;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import javax.ws.rs.core.Response;
public class HttpClientManager {
private static final int DEFAULT_BORROW_MAX_TIME_MS = 3000;
private static final int DEFAULT_MAX_TOTAL = 100;
private static final int DEFAULT_MAX_IDLE = 100;
private ClientConfiguration clientConfiguration;
private GenericObjectPoolConfig objectPoolConfig;
private AtomicReference<GenericObjectPool<HttpClient>> objectPoolAtomicReference = new AtomicReference<GenericObjectPool<HttpClient>>();
private int borrowMaxWaitMillis = DEFAULT_BORROW_MAX_TIME_MS;
private StreamingManager streamingManager = new DefaultStreamingManager(this);
public HttpClientManager() {
objectPoolConfig = new GenericObjectPoolConfig();
objectPoolConfig.setMaxTotal(DEFAULT_MAX_TOTAL);
objectPoolConfig.setMaxIdle(DEFAULT_MAX_IDLE);
}
public HttpClientManager(ClientConfiguration clientConfiguration) {
this();
this.clientConfiguration = clientConfiguration;
}
public void setClientConfiguration(ClientConfiguration clientConfiguration) {
this.clientConfiguration = clientConfiguration;
}
public void setObjectPoolConfig(GenericObjectPoolConfig objectPoolConfig) {
this.objectPoolConfig = objectPoolConfig;
}
public void setBorrowMaxWaitMillis(int borrowMaxWaitMillis) {
this.borrowMaxWaitMillis = borrowMaxWaitMillis;
}
public void setStreamingManager(StreamingManager streamingManager) {
this.streamingManager = streamingManager;
}
public void setCheckPeriodMillis(long checkPeriodMillis) {
streamingManager.setCheckPeriodMillis(checkPeriodMillis);
}
public <T> List<T> requestMetaDataList(Class<T> clazz, QueryPart<T> query) {
HttpClient httpClient = borrowClient();
try {
return httpClient.requestMetaDataList(clazz, query);
} finally {
returnClient(httpClient);
}
}
public <T> T requestMetaDataObject(Class<T> clazz, QueryPart<T> query) {
HttpClient httpClient = borrowClient();
try {
return httpClient.requestMetaDataObject(clazz, query);
} finally {
returnClient(httpClient);
}
}
public <E> boolean updateMetaData(QueryPart query, RequestProcessor<E> requestProcessor) {
HttpClient httpClient = borrowClient();
try {
return httpClient.updateMetaData(query, requestProcessor);
} finally {
returnClient(httpClient);
}
}
public boolean updateData(QueryPart query, RequestProcessor requestProcessor) {
HttpClient httpClient = borrowClient();
try {
return httpClient.updateData(query, requestProcessor);
} finally {
returnClient(httpClient);
}
}
public boolean updateData(QueryPart query, String data) {
HttpClient httpClient = borrowClient();
try {
return httpClient.updateData(query, data);
} finally {
returnClient(httpClient);
}
}
public <T, E> List<T> requestDataList(Class<T> clazz, QueryPart<T> query, RequestProcessor<E> requestProcessor) {
HttpClient httpClient = borrowClient();
try {
return httpClient.requestDataList(clazz, query, requestProcessor);
} finally {
returnClient(httpClient);
}
}
public <T, E> T requestData(QueryPart<T> query, RequestProcessor<E> requestProcessor, ResponseDataExtractor<T> responseDataExtractor) {
HttpClient httpClient = borrowClient();
try {
Response response = httpClient.request(query, requestProcessor);
return responseDataExtractor.extract(response);
} finally {
returnClient(httpClient);
}
}
public <T> T requestData(QueryPart<T> query, String data, ResponseDataExtractor<T> responseDataExtractor) {
HttpClient httpClient = borrowClient();
try {
Response response = httpClient.request(query, data);
return responseDataExtractor.extract(response);
} finally {
returnClient(httpClient);
}
}
public <T, E> T requestData(Class<T> clazz, QueryPart<T> query, RequestProcessor<E> requestProcessor) {
HttpClient httpClient = borrowClient();
try {
return httpClient.requestData(clazz, query, requestProcessor);
} finally {
returnClient(httpClient);
}
}
public InputStream requestInputStream(QueryPart query, RequestProcessor requestProcessor) {
HttpClient httpClient = borrowClient();
try {
return httpClient.requestInputStream(query, requestProcessor);
} finally {
returnClient(httpClient);
}
}
private HttpClient borrowClient() {
GenericObjectPool<HttpClient> objectPool = createObjectPool();
HttpClient httpClient;
try {
httpClient = objectPool.borrowObject(borrowMaxWaitMillis);
} catch (Exception e) {
throw new AtsdClientException("Could not borrow http client from pool", e);
}
return httpClient;
}
private void returnClient(HttpClient httpClient) {
objectPoolAtomicReference.get().returnObject(httpClient);
}
private GenericObjectPool<HttpClient> createObjectPool() {
GenericObjectPool<HttpClient> httpClientGenericObjectPool = objectPoolAtomicReference.get();
if (httpClientGenericObjectPool == null) {
httpClientGenericObjectPool = new GenericObjectPool<HttpClient>(new HttpClientBasePooledObjectFactory(), objectPoolConfig);
objectPoolAtomicReference.compareAndSet(null, httpClientGenericObjectPool);
}
return objectPoolAtomicReference.get();
}
public void close() {
GenericObjectPool<HttpClient> pool = objectPoolAtomicReference.get();
if (pool != null) {
pool.close();
}
streamingManager.close();
}
public void send(PlainCommand plainCommand) {
streamingManager.send(plainCommand);
}
public boolean canSendPlainCommand() {
return streamingManager.canSend();
}
public List<String> removeSavedPlainCommands() {
return streamingManager.removeSavedPlainCommands();
}
private class HttpClientBasePooledObjectFactory extends BasePooledObjectFactory<HttpClient> {
@Override
public HttpClient create() throws Exception {
return new HttpClient(clientConfiguration);
}
@Override
public PooledObject<HttpClient> wrap(HttpClient httpClient) {
return new DefaultPooledObject<HttpClient>(httpClient);
}
@Override
public void destroyObject(PooledObject<HttpClient> p) throws Exception {
p.getObject().close();
}
}
public ClientConfiguration getClientConfiguration() {
return clientConfiguration;
}
}