com.huawei.openstack4j.connectors.http.HttpCommand Maven / Gradle / Ivy
The newest version!
/*******************************************************************************
* Copyright 2016 ContainX and OpenStack4j
*
* Licensed 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 com.huawei.openstack4j.connectors.http;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.Proxy;
import java.net.Proxy.Type;
import java.net.URL;
import java.net.URLEncoder;
import java.util.List;
import java.util.Map;
import javax.net.ssl.HttpsURLConnection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.io.ByteStreams;
import com.google.common.net.MediaType;
import com.huawei.openstack4j.core.transport.Config;
import com.huawei.openstack4j.core.transport.HttpRequest;
import com.huawei.openstack4j.core.transport.HttpResponse;
import com.huawei.openstack4j.core.transport.ObjectMapperSingleton;
import com.huawei.openstack4j.core.transport.UntrustedSSL;
import com.huawei.openstack4j.core.transport.functions.EndpointURIFromRequestFunction;
/**
* HttpCommand is responsible for executing the actual request driven by the
* HttpExecutor.
*
* @param
*/
public final class HttpCommand {
private static final Logger LOG = LoggerFactory.getLogger(HttpCommand.class);
private HttpRequest request;
private URL connectionUrl;
private HttpURLConnection connection;
private int retries;
private HttpCommand(HttpRequest request) {
this.request = request;
}
/**
* Creates a new HttpCommand from the given request
*
* @param request the request
* @return the command
*/
public static HttpCommand create(HttpRequest request) {
HttpCommand command = new HttpCommand(request);
command.initialize();
return command;
}
private void initialize() {
try {
populateQueryParams();
populateHeaders();
} catch (Exception ex) {
LOG.error(ex.getMessage(), ex);
}
}
/**
* Executes the command and returns the Response
*
* @return the response
* @throws Exception
*/
public HttpResponse execute() throws Exception {
byte[] requestBody = null;
if (request.getEntity() != null) {
if (InputStream.class.isAssignableFrom(request.getEntity().getClass())) {
requestBody = ByteStreams.toByteArray((InputStream) request.getEntity());
} else {
String content = ObjectMapperSingleton.getContext(request.getEntity().getClass()).writer()
.writeValueAsString(request.getEntity());
requestBody = content.getBytes();
}
} else if (request.hasJson()) {
requestBody = request.getJson().getBytes();
}
try {
// connection.setRequestMethod(request.getMethod().name());
setRequestMethodUsingWorkaroundForJREBug(connection, request.getMethod().name());
if (requestBody != null) {
connection.setDoOutput(true);
BufferedOutputStream out = new BufferedOutputStream(connection.getOutputStream());
out.write(requestBody);
out.flush();
}
byte[] data = null;
int status = connection.getResponseCode();
if (status >= 200 && status < 300) {
data = ByteStreams.toByteArray(connection.getInputStream());
}
return HttpResponseImpl.wrap(connection.getHeaderFields(), status, connection.getResponseMessage(), data);
} catch (IOException e) {
LOG.error(e.getMessage(), e);
throw e;
} finally {
connection.disconnect();
}
}
/**
* @see https://java.net/jira/browse/JERSEY-639
*
* @param httpURLConnection the HttpURLConnection
* @param method the methods name (GET, PUT, POST,... exception is thrown when trying to do a PATCH)
*/
private static final void setRequestMethodUsingWorkaroundForJREBug(final HttpURLConnection httpURLConnection,
final String method) {
try {
httpURLConnection.setRequestMethod(method);
// Check whether we are running on a buggy JRE
} catch (final ProtocolException pe) {
try {
final Class> httpURLConnectionClass = httpURLConnection.getClass();
final Class> parentClass = httpURLConnectionClass.getSuperclass();
final Field methodField;
// If the implementation class is an HTTPS URL Connection, we
// need to go up one level higher in the heirarchy to modify the
// 'method' field.
if (parentClass == HttpsURLConnection.class) {
methodField = parentClass.getSuperclass().getDeclaredField("method");
} else {
methodField = parentClass.getDeclaredField("method");
}
methodField.setAccessible(true);
methodField.set(httpURLConnection, method);
} catch (final Exception e) {
throw new RuntimeException(e);
}
}
}
/**
* @return true if a request entity has been set
*/
public boolean hasEntity() {
return request.getEntity() != null;
}
/**
* @return current retry execution count for this command
*/
public int getRetries() {
return retries;
}
/**
* @return incremement's the retry count and returns self
*/
public HttpCommand incrementRetriesAndReturn() {
initialize();
retries++;
return this;
}
public HttpRequest getRequest() {
return request;
}
private void populateQueryParams() throws MalformedURLException {
StringBuilder url = new StringBuilder();
url.append(new EndpointURIFromRequestFunction().apply(request));
if (!request.hasQueryParams()) {
connectionUrl = new URL(url.toString());
return;
}
url.append("?");
for (Map.Entry> entry : request.getQueryParams().entrySet()) {
for (Object o : entry.getValue()) {
try {
url.append(URLEncoder.encode(entry.getKey(), "UTF-8")).append("=")
.append(URLEncoder.encode(String.valueOf(o), "UTF-8"));
url.append("&");
} catch (UnsupportedEncodingException e) {
LOG.error(e.getMessage(), e);
}
}
}
if (url.charAt(url.length() - 1) == '&') {
url.deleteCharAt(url.length() - 1);
}
connectionUrl = new URL(url.toString());
}
private void populateHeaders() throws IOException {
if (request.getConfig().isIgnoreSSLVerification()) {
HttpsURLConnection.setDefaultHostnameVerifier(UntrustedSSL.getHostnameVerifier());
HttpsURLConnection.setDefaultSSLSocketFactory(UntrustedSSL.getSSLContext().getSocketFactory());
}
if (request.getConfig().getSslContext() != null) {
HttpsURLConnection.setDefaultSSLSocketFactory(request.getConfig().getSslContext().getSocketFactory());
}
if (request.getConfig() != null && request.getConfig().getProxy() != null) {
Config config = request.getConfig();
Proxy proxy = new Proxy(Type.HTTP,
new InetSocketAddress(config.getProxy().getRawHost(), config.getProxy().getPort()));
connection = (HttpURLConnection) connectionUrl.openConnection(proxy);
} else {
connection = (HttpURLConnection) connectionUrl.openConnection();
}
connection.setRequestProperty("Content-Type", request.getContentType());
connection.setRequestProperty("Accept", MediaType.JSON_UTF_8.toString());
if (!request.hasHeaders()) {
return;
}
for (Map.Entry h : request.getHeaders().entrySet()) {
connection.setRequestProperty(h.getKey(), String.valueOf(h.getValue()));
}
}
}