blob: 08c6f4fceec44fa5077096fe2e680ca6b5caaf14 [file] [log] [blame]
/*
* 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.dubbo.remoting.http.restclient;
import org.apache.commons.io.IOUtils;
import org.apache.dubbo.remoting.http.RequestTemplate;
import org.apache.dubbo.remoting.http.RestClient;
import org.apache.dubbo.remoting.http.RestResult;
import org.apache.dubbo.remoting.http.config.HttpClientConfig;
import org.apache.http.Header;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpHead;
import org.apache.http.client.methods.HttpOptions;
import org.apache.http.client.methods.HttpPatch;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.methods.HttpTrace;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
public class HttpClientRestClient implements RestClient {
private final CloseableHttpClient closeableHttpClient;
private final HttpClientConfig httpClientConfig;
public HttpClientRestClient(HttpClientConfig clientConfig) {
closeableHttpClient = createHttpClient();
httpClientConfig = clientConfig;
}
@Override
public CompletableFuture<RestResult> send(RequestTemplate requestTemplate) {
HttpRequestBase httpRequest = null;
String httpMethod = requestTemplate.getHttpMethod();
httpRequest = createHttpUriRequest(httpMethod, requestTemplate);
if (httpRequest instanceof HttpEntityEnclosingRequest) {
((HttpEntityEnclosingRequestBase) httpRequest)
.setEntity(new ByteArrayEntity(requestTemplate.getSerializedBody()));
}
Map<String, Collection<String>> allHeaders = requestTemplate.getAllHeaders();
allHeaders.remove("Content-Length");
// header
for (String headerName : allHeaders.keySet()) {
Collection<String> headerValues = allHeaders.get(headerName);
for (String headerValue : headerValues) {
httpRequest.addHeader(headerName, headerValue);
}
}
httpRequest.setConfig(getRequestConfig(httpClientConfig));
CompletableFuture<RestResult> future = new CompletableFuture<>();
try {
CloseableHttpResponse response = closeableHttpClient.execute(httpRequest);
future.complete(new RestResult() {
@Override
public String getContentType() {
Header header = response.getFirstHeader("Content-Type");
return header == null ? null : header.getValue();
}
@Override
public byte[] getBody() throws IOException {
if (response.getEntity() == null) {
return new byte[0];
}
return IOUtils.toByteArray(response.getEntity().getContent());
}
@Override
public Map<String, List<String>> headers() {
return Arrays.stream(response.getAllHeaders())
.collect(Collectors.toMap(Header::getName, h -> Collections.singletonList(h.getValue())));
}
@Override
public byte[] getErrorResponse() throws IOException {
return getBody();
}
@Override
public int getResponseCode() {
return response.getStatusLine().getStatusCode();
}
@Override
public String getMessage() throws IOException {
return appendErrorMessage(
response.getStatusLine().getReasonPhrase(), new String(getErrorResponse()));
}
});
} catch (IOException e) {
future.completeExceptionally(e);
}
return future;
}
private RequestConfig getRequestConfig(HttpClientConfig clientConfig) {
// TODO config
return RequestConfig.custom().build();
}
@Override
public void close() {
try {
closeableHttpClient.close();
} catch (IOException e) {
}
}
@Override
public void close(int timeout) {}
@Override
public boolean isClosed() {
// TODO close judge
return true;
}
public CloseableHttpClient createHttpClient() {
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
return HttpClients.custom().setConnectionManager(connectionManager).build();
}
protected HttpRequestBase createHttpUriRequest(String httpMethod, RequestTemplate requestTemplate) {
String uri = requestTemplate.getURL();
HttpRequestBase httpUriRequest = null;
if (HttpGet.METHOD_NAME.equals(httpMethod)) {
httpUriRequest = new HttpGet(uri);
} else if (HttpHead.METHOD_NAME.equals(httpMethod)) {
httpUriRequest = new HttpHead(uri);
} else if (HttpPost.METHOD_NAME.equals(httpMethod)) {
httpUriRequest = new HttpPost(uri);
} else if (HttpPut.METHOD_NAME.equals(httpMethod)) {
httpUriRequest = new HttpPut(uri);
} else if (HttpPatch.METHOD_NAME.equals(httpMethod)) {
httpUriRequest = new HttpPatch(uri);
} else if (HttpDelete.METHOD_NAME.equals(httpMethod)) {
httpUriRequest = new HttpDelete(uri);
} else if (HttpOptions.METHOD_NAME.equals(httpMethod)) {
httpUriRequest = new HttpOptions(uri);
} else if (HttpTrace.METHOD_NAME.equals(httpMethod)) {
httpUriRequest = new HttpTrace(uri);
} else {
throw new IllegalArgumentException("Invalid HTTP method: " + httpMethod);
}
return httpUriRequest;
}
}