// Path: src/main/java/com/qcloud/cos/ClientConfig.java
// public class ClientConfig {
// 	// cos server的域名地址
//     private static final String COS_ENDPOINT = "http://web.file.myqcloud.com/files/v1";
//     // 多次签名的默认过期时间,单位秒
//     private static final int DEFAULT_SIGN_EXPIRED = 300;
//     // 默认的最大重试次数(发生了socketException时)
//     private static final int DEFAULT_MAX_RETRIES = 3;
//     // 默认的获取连接的超时时间
//     private static final int DEFAULT_CONNECTION_REQUEST_TIMEOUT = -1;
//     // 默认连接超时, 单位ms
//     private static final int DEFAULT_CONNECTION_TIMEOUT = 30 * 1000;
//     // 默认的SOCKET读取超时时间, 默认毫秒
//     private static final int DEFAULT_SOCKET_TIMEOUT = 30 * 1000;
//     // 默认的维护最大HTTP连接数
//     private static final int DEFAULT_MAX_CONNECTIONS_COUNT = 100;
//     // 默认的user_agent标识
//     private static final String DEFAULT_USER_AGENT = "cos-java-sdk-v3.3";
// 
//     
//     private String cosEndPoint = COS_ENDPOINT;
//     private int signExpired = DEFAULT_SIGN_EXPIRED;
//     private int maxFailedRetry = DEFAULT_MAX_RETRIES;
//     private int connectionRequestTimeout = DEFAULT_CONNECTION_REQUEST_TIMEOUT;
//     private int connectionTimeout = DEFAULT_CONNECTION_TIMEOUT;
//     private int socketTimeout = DEFAULT_SOCKET_TIMEOUT;
//     private int maxConnectionsCount = DEFAULT_MAX_CONNECTIONS_COUNT;
//     private String userAgent = DEFAULT_USER_AGENT;
//  
// 
//     public int getMaxFailedRetry() {
//         return maxFailedRetry;
//     }
// 
//     public void setMaxFailedRetry(int maxFailedRetry) {
//         this.maxFailedRetry = maxFailedRetry;
//     }
//     
// 
//     public int getSignExpired() {
// 		return signExpired;
// 	}
// 
// 	public void setSignExpired(int signExpired) {
// 		this.signExpired = signExpired;
// 	}
// 
// 	public int getConnectionRequestTimeout() {
//         return connectionRequestTimeout;
//     }
// 
//     public void setConnectionRequestTimeout(int connectionRequestTimeout) {
//         this.connectionRequestTimeout = connectionRequestTimeout;
//     }
// 
//     public int getConnectionTimeout() {
//         return connectionTimeout;
//     }
// 
//     public void setConnectionTimeout(int connectionTimeout) {
//         this.connectionTimeout = connectionTimeout;
//     }
// 
//     public int getSocketTimeout() {
//         return socketTimeout;
//     }
// 
//     public void setSocketTimeout(int socketTimeout) {
//         this.socketTimeout = socketTimeout;
//     }
// 
//     public int getMaxConnectionsCount() {
//         return maxConnectionsCount;
//     }
// 
//     public void setMaxConnectionsCount(int maxConnectionsCount) {
//         this.maxConnectionsCount = maxConnectionsCount;
//     }
// 
//     public String getUserAgent() {
//         return userAgent;
//     }
// 
//     public void setUserAgent(String userAgent) {
//         this.userAgent = userAgent;
//     }
// 
//     public String getCosEndPoint() {
//         return cosEndPoint;
//     }
// 
//     public void setCosEndPoint(String cosEndpoint) {
//         this.cosEndPoint = cosEndpoint;
//     }
//     
// }
// 
// Path: src/main/java/com/qcloud/cos/exception/AbstractCosException.java
// public abstract class AbstractCosException extends Exception {
// 
//     private static final long serialVersionUID = 7547532865194837136L;
//     
//     private CosExceptionType type;
// 
//     public AbstractCosException(CosExceptionType type, String message) {
//         super(message);
//         this.type = type;
//     }
// 
//     public CosExceptionType getType() {
//         return type;
//     }
//     
//     @Override
//     public String toString() {
//         JSONObject responseObj = new JSONObject();
//         responseObj.put(ResponseBodyKey.CODE, type.getErrorCode());
//         responseObj.put(ResponseBodyKey.MESSAGE, getMessage());
//         return responseObj.toString();
//     }
//     
// }
// 
// Path: src/main/java/com/qcloud/cos/exception/ParamException.java
// public class ParamException extends AbstractCosException {
// 
//     private static final long serialVersionUID = 216921496331691543L;
// 
//     public ParamException(String message) {
//         super(CosExceptionType.PARAM_EXCEPTION, message);
//     }
//     
// }


import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import com.qcloud.cos.ClientConfig;
import com.qcloud.cos.exception.AbstractCosException;
import com.qcloud.cos.exception.ParamException;
    protected RequestConfig requestConfig;

    public AbstractCosHttpClient(ClientConfig config) {
        super();
        this.config = config;
        this.connectionManager = new PoolingHttpClientConnectionManager();
        this.connectionManager.setMaxTotal(config.getMaxConnectionsCount());
        this.connectionManager.setDefaultMaxPerRoute(config.getMaxConnectionsCount());
        this.httpClient = HttpClients.custom().setConnectionManager(connectionManager).build();
        this.requestConfig = RequestConfig.custom()
                                          .setConnectionRequestTimeout(this.config.getConnectionRequestTimeout())
                                          .setConnectTimeout(this.config.getConnectionTimeout())
                                          .setSocketTimeout(this.config.getSocketTimeout())
                                          .build();
        this.idleConnectionMonitor = new IdleConnectionMonitorThread(this.connectionManager);
        this.idleConnectionMonitor.start();
    }

    protected abstract String sendPostRequest(HttpRequest httpRequest) throws AbstractCosException;

    protected abstract String sendGetRequest(HttpRequest httpRequest) throws AbstractCosException;

    public String sendHttpRequest(HttpRequest httpRequest) throws AbstractCosException {

        HttpMethod method = httpRequest.getMethod();
        if (method == HttpMethod.POST) {
            return sendPostRequest(httpRequest);
        } else if (method == HttpMethod.GET) {
            return sendGetRequest(httpRequest);
        } else {
// Path: src/main/java/com/qcloud/cos/ClientConfig.java
// public class ClientConfig {
// 	// cos server的域名地址
//     private static final String COS_ENDPOINT = "http://web.file.myqcloud.com/files/v1";
//     // 多次签名的默认过期时间,单位秒
//     private static final int DEFAULT_SIGN_EXPIRED = 300;
//     // 默认的最大重试次数(发生了socketException时)
//     private static final int DEFAULT_MAX_RETRIES = 3;
//     // 默认的获取连接的超时时间
//     private static final int DEFAULT_CONNECTION_REQUEST_TIMEOUT = -1;
//     // 默认连接超时, 单位ms
//     private static final int DEFAULT_CONNECTION_TIMEOUT = 30 * 1000;
//     // 默认的SOCKET读取超时时间, 默认毫秒
//     private static final int DEFAULT_SOCKET_TIMEOUT = 30 * 1000;
//     // 默认的维护最大HTTP连接数
//     private static final int DEFAULT_MAX_CONNECTIONS_COUNT = 100;
//     // 默认的user_agent标识
//     private static final String DEFAULT_USER_AGENT = "cos-java-sdk-v3.3";
// 
//     
//     private String cosEndPoint = COS_ENDPOINT;
//     private int signExpired = DEFAULT_SIGN_EXPIRED;
//     private int maxFailedRetry = DEFAULT_MAX_RETRIES;
//     private int connectionRequestTimeout = DEFAULT_CONNECTION_REQUEST_TIMEOUT;
//     private int connectionTimeout = DEFAULT_CONNECTION_TIMEOUT;
//     private int socketTimeout = DEFAULT_SOCKET_TIMEOUT;
//     private int maxConnectionsCount = DEFAULT_MAX_CONNECTIONS_COUNT;
//     private String userAgent = DEFAULT_USER_AGENT;
//  
// 
//     public int getMaxFailedRetry() {
//         return maxFailedRetry;
//     }
// 
//     public void setMaxFailedRetry(int maxFailedRetry) {
//         this.maxFailedRetry = maxFailedRetry;
//     }
//     
// 
//     public int getSignExpired() {
// 		return signExpired;
// 	}
// 
// 	public void setSignExpired(int signExpired) {
// 		this.signExpired = signExpired;
// 	}
// 
// 	public int getConnectionRequestTimeout() {
//         return connectionRequestTimeout;
//     }
// 
//     public void setConnectionRequestTimeout(int connectionRequestTimeout) {
//         this.connectionRequestTimeout = connectionRequestTimeout;
//     }
// 
//     public int getConnectionTimeout() {
//         return connectionTimeout;
//     }
// 
//     public void setConnectionTimeout(int connectionTimeout) {
//         this.connectionTimeout = connectionTimeout;
//     }
// 
//     public int getSocketTimeout() {
//         return socketTimeout;
//     }
// 
//     public void setSocketTimeout(int socketTimeout) {
//         this.socketTimeout = socketTimeout;
//     }
// 
//     public int getMaxConnectionsCount() {
//         return maxConnectionsCount;
//     }
// 
//     public void setMaxConnectionsCount(int maxConnectionsCount) {
//         this.maxConnectionsCount = maxConnectionsCount;
//     }
// 
//     public String getUserAgent() {
//         return userAgent;
//     }
// 
//     public void setUserAgent(String userAgent) {
//         this.userAgent = userAgent;
//     }
// 
//     public String getCosEndPoint() {
//         return cosEndPoint;
//     }
// 
//     public void setCosEndPoint(String cosEndpoint) {
//         this.cosEndPoint = cosEndpoint;
//     }
//     
// }
// 
// Path: src/main/java/com/qcloud/cos/exception/AbstractCosException.java
// public abstract class AbstractCosException extends Exception {
// 
//     private static final long serialVersionUID = 7547532865194837136L;
//     
//     private CosExceptionType type;
// 
//     public AbstractCosException(CosExceptionType type, String message) {
//         super(message);
//         this.type = type;
//     }
// 
//     public CosExceptionType getType() {
//         return type;
//     }
//     
//     @Override
//     public String toString() {
//         JSONObject responseObj = new JSONObject();
//         responseObj.put(ResponseBodyKey.CODE, type.getErrorCode());
//         responseObj.put(ResponseBodyKey.MESSAGE, getMessage());
//         return responseObj.toString();
//     }
//     
// }
// 
// Path: src/main/java/com/qcloud/cos/exception/ParamException.java
// public class ParamException extends AbstractCosException {
// 
//     private static final long serialVersionUID = 216921496331691543L;
// 
//     public ParamException(String message) {
//         super(CosExceptionType.PARAM_EXCEPTION, message);
//     }
//     
// }


// Path: src/main/java/com/qcloud/cos/http/AbstractCosHttpClient.java
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import com.qcloud.cos.ClientConfig;
import com.qcloud.cos.exception.AbstractCosException;
import com.qcloud.cos.exception.ParamException;

    protected RequestConfig requestConfig;

    public AbstractCosHttpClient(ClientConfig config) {
        super();
        this.config = config;
        this.connectionManager = new PoolingHttpClientConnectionManager();
        this.connectionManager.setMaxTotal(config.getMaxConnectionsCount());
        this.connectionManager.setDefaultMaxPerRoute(config.getMaxConnectionsCount());
        this.httpClient = HttpClients.custom().setConnectionManager(connectionManager).build();
        this.requestConfig = RequestConfig.custom()
                                          .setConnectionRequestTimeout(this.config.getConnectionRequestTimeout())
                                          .setConnectTimeout(this.config.getConnectionTimeout())
                                          .setSocketTimeout(this.config.getSocketTimeout())
                                          .build();
        this.idleConnectionMonitor = new IdleConnectionMonitorThread(this.connectionManager);
        this.idleConnectionMonitor.start();
    }

    protected abstract String sendPostRequest(HttpRequest httpRequest) throws AbstractCosException;

    protected abstract String sendGetRequest(HttpRequest httpRequest) throws AbstractCosException;

    public String sendHttpRequest(HttpRequest httpRequest) throws AbstractCosException {

        HttpMethod method = httpRequest.getMethod();
        if (method == HttpMethod.POST) {
            return sendPostRequest(httpRequest);
        } else if (method == HttpMethod.GET) {
            return sendGetRequest(httpRequest);
        } else {
            throw new ParamException("Unsupported Http Method");