Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright 2020 Gerald Curley
*
* 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.opsmatters.bitly.api.services;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Map;
import java.util.List;
import java.util.logging.Logger;
import java.util.logging.Level;
import java.lang.reflect.Type;
import com.google.gson.reflect.TypeToken;
import com.google.gson.Gson;
import com.google.common.base.Optional;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPatch;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.HttpMessage;
import org.apache.http.HttpResponse;
import org.apache.http.HttpEntity;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.ContentType;
import com.opsmatters.bitly.BitlyException;
import com.opsmatters.bitly.api.model.ErrorResponse;
/**
* Base class for HTTP operations using API calls.
*
* @author Gerald Curley (opsmatters)
*/
public class HttpContext
{
private static final Logger logger = Logger.getLogger(HttpContext.class.getName());
protected static final Type ERROR = new TypeToken(){}.getType();
private String protocol;
private String hostname;
private int port;
private Gson gson = new Gson();
private static CloseableHttpClient client;
/**
* Constructor that takes a protocol, hostname and port.
* @param protocol The protocol used to connect to the server
* @param hostname The hostname of the server
* @param port The port of the server
*/
public HttpContext(String protocol, String hostname, int port)
{
this.protocol = protocol;
this.hostname = hostname;
this.port = port;
if(client == null)
client = HttpClients.custom().setConnectionManager(new PoolingHttpClientConnectionManager()).build();
}
/**
* Build the URL from the protocol://hostname:port + relativePath
* @param relativePath The path of the resource (should always start with a "/")
* @return The URL to call
*/
String buildUrl(String relativePath)
{
return String.format("%s://%s:%d%s", protocol, hostname, port, relativePath);
}
/**
* Build the URI from the protocol://hostname:port + relativePath.
* @param relativePath The path of the resource (should always start with a "/")
* @return The URI to call
*/
URI buildUri(String relativePath)
{
URI uri = null;
try
{
uri = new URI(buildUrl(relativePath));
}
catch(URISyntaxException e)
{
logger.severe("Problem constructing URI: "+e.getClass().getName()+e.getMessage());
}
return uri;
}
/**
* Execute a GET call against the partial URL and deserialize the results.
* @param The type parameter used for the return object
* @param partialUrl The partial URL to build
* @param returnType The expected return type
* @return The return type
* @throws IOException if there is a communication error.
* @throws URISyntaxException if there is a format error in the URL.
*/
public Optional GET(String partialUrl, Type returnType) throws IOException, URISyntaxException
{
URI uri = buildUri(partialUrl);
return executeGetRequest(uri, returnType);
}
/**
* Execute a GET call against the partial URL and deserialize the results.
* @param The type parameter used for the return object
* @param partialUrl The partial URL to build
* @param returnType The expected return type
* @param headers A set of headers to add to the request
* @param queryParams A set of query parameters to add to the request
* @return The return type
* @throws IOException if there is a communication error.
* @throws URISyntaxException if there is a format error in the URL.
*/
public Optional GET(String partialUrl, Map headers, List queryParams, Type returnType)
throws IOException, URISyntaxException
{
URI uri = buildUri(partialUrl);
return executeGetRequest(uri, headers, queryParams, returnType);
}
/**
* Execute a POST call against the partial URL.
* @param partialUrl The partial URL to build
* @param payload The object to use for the POST
* @return The response to the POST
* @throws IOException if there is a communication error.
*/
public Optional POST(String partialUrl, Object payload) throws IOException
{
URI uri = buildUri(partialUrl);
return executePostRequest(uri, payload);
}
/**
* Execute a POST call against the partial URL.
* @param partialUrl The partial URL to build
* @param payload The object to use for the POST
* @param headers A set of headers to add to the request
* @return The response to the POST
* @throws IOException if there is a communication error.
*/
public Optional POST(String partialUrl, Object payload, Map headers) throws IOException
{
URI uri = buildUri(partialUrl);
return executePostRequest(uri, payload, headers);
}
/**
* Execute a POST call against the partial URL.
* @param The type parameter used for the return object
* @param partialUrl The partial URL to build
* @param payload The object to use for the POST
* @param returnType The expected return type
* @return The return type
* @throws IOException if there is a communication error.
*/
public Optional POST(String partialUrl, Object payload, Type returnType) throws IOException
{
URI uri = buildUri(partialUrl);
return executePostRequest(uri, payload, returnType);
}
/**
* Execute a POST call against the partial URL.
* @param The type parameter used for the return object
* @param partialUrl The partial URL to build
* @param payload The object to use for the POST
* @param headers A set of headers to add to the request
* @param returnType The expected return type
* @return The return type
* @throws IOException if there is a communication error.
*/
public Optional POST(String partialUrl, Object payload, Map headers, Type returnType) throws IOException
{
URI uri = buildUri(partialUrl);
return executePostRequest(uri, payload, headers, returnType);
}
/**
* Execute a PATCH call against the partial URL.
* @param partialUrl The partial URL to build
* @param payload The object to use for the PATCH
* @throws IOException if there is a communication error.
* @throws URISyntaxException if there is a format error in the URL.
*/
public void PATCH(String partialUrl, Object payload) throws IOException, URISyntaxException
{
URI uri = buildUri(partialUrl);
executePatchRequest(uri, payload);
}
/**
* Execute a PATCH call against the partial URL.
* @param partialUrl The partial URL to build
* @param payload The object to use for the PATCH
* @param headers A set of headers to add to the request
* @param queryParams A set of query parameters to add to the request
* @throws IOException if there is a communication error.
* @throws URISyntaxException if there is a format error in the URL.
*/
public void PATCH(String partialUrl, Object payload, Map headers, List queryParams)
throws IOException, URISyntaxException
{
URI uri = buildUri(partialUrl);
executePatchRequest(uri, payload, headers, queryParams);
}
/**
* Execute a PATCH call against the partial URL.
* @param The type parameter used for the return object
* @param partialUrl The partial URL to build
* @param payload The object to use for the PATCH
* @param returnType The expected return type
* @return The return type
* @throws IOException if there is a communication error.
* @throws URISyntaxException if there is a format error in the URL.
*/
public Optional PATCH(String partialUrl, Object payload, Type returnType)
throws IOException, URISyntaxException
{
URI uri = buildUri(partialUrl);
return executePatchRequest(uri, payload, null, null, returnType);
}
/**
* Execute a PATCH call against the partial URL.
* @param The type parameter used for the return object
* @param partialUrl The partial URL to build
* @param payload The object to use for the PATCH
* @param headers A set of headers to add to the request
* @param queryParams A set of query parameters to add to the request
* @param returnType The expected return type
* @return The return type
* @throws IOException if there is a communication error.
* @throws URISyntaxException if there is a format error in the URL.
*/
public Optional PATCH(String partialUrl, Object payload, Map headers,
List queryParams, Type returnType)
throws IOException, URISyntaxException
{
URI uri = buildUri(partialUrl);
return executePatchRequest(uri, payload, headers, queryParams, returnType);
}
/**
* Execute a DELETE call against the partial URL.
* @param partialUrl The partial URL to build
* @throws IOException if there is a communication error.
* @throws URISyntaxException if there is a format error in the URL.
*/
public void DELETE(String partialUrl) throws IOException, URISyntaxException
{
URI uri = buildUri(partialUrl);
executeDeleteRequest(uri);
}
/**
* Execute a DELETE call against the partial URL.
* @param partialUrl The partial URL to build
* @param headers A set of headers to add to the request
* @param queryParams A set of query parameters to add to the request
* @throws IOException if there is a communication error.
* @throws URISyntaxException if there is a format error in the URL.
*/
public void DELETE(String partialUrl, Map headers, List queryParams)
throws IOException, URISyntaxException
{
URI uri = buildUri(partialUrl);
executeDeleteRequest(uri, headers, queryParams);
}
/**
* Execute a GET request and return the result.
* @param The type parameter used for the return object
* @param uri The URI to call
* @param returnType The type to marshall the result back into
* @return The return type
* @throws IOException if there is a communication error.
* @throws URISyntaxException if there is a format error in the URL.
*/
protected Optional executeGetRequest(URI uri, Type returnType) throws IOException, URISyntaxException
{
return executeGetRequest(uri, null, null, returnType);
}
/**
* Execute a GET request and return the result.
* @param The type parameter used for the return object
* @param uri The URI to call
* @param returnType The type to marshall the result back into
* @param headers A set of headers to add to the request
* @param queryParams A set of query parameters to add to the request
* @return The return type
* @throws IOException if there is a communication error.
* @throws URISyntaxException if there is a format error in the URL.
*/
protected Optional executeGetRequest(URI uri, Map headers, List queryParams, Type returnType)
throws IOException, URISyntaxException
{
URIBuilder builder = new URIBuilder(uri);
builder = applyQueryParams(builder, queryParams);
HttpGet request = new HttpGet(builder.build());
applyHeaders(request, headers);
HttpResponse response = client.execute(request);
handleResponseError("GET", uri, response);
logResponse(uri, response);
return extractEntityFromResponse(response, returnType);
}
/**
* Execute a POST request.
* @param uri The URI to call
* @param obj The object to use for the POST
* @return The response to the POST
* @throws IOException if there is a communication error.
*/
protected Optional executePostRequest(URI uri, Object obj) throws IOException
{
return executePostRequest(uri, obj, (Map)null);
}
/**
* Execute a POST request.
* @param uri The URI to call
* @param obj The object to use for the POST
* @param headers A set of headers to add to the request
* @return The response to the POST
* @throws IOException if there is a communication error.
*/
protected Optional executePostRequest(URI uri, Object obj, Map headers) throws IOException
{
HttpPost request = new HttpPost(uri);
applyHeaders(request, headers);
request.setEntity(new StringEntity(gson.toJson(obj), ContentType.APPLICATION_JSON));
HttpResponse response = client.execute(request);
handleResponseError("POST", uri, response);
logResponse(uri, response);
return Optional.of(response);
}
/**
* Execute a POST request with a return object.
* @param The type parameter used for the return object
* @param uri The URI to call
* @param obj The object to use for the POST
* @param returnType The type to marshall the result back into
* @return The return type
* @throws IOException if there is a communication error.
*/
protected Optional executePostRequest(URI uri, Object obj, Type returnType) throws IOException
{
return executePostRequest(uri, obj, null, returnType);
}
/**
* Execute a POST request with a return object.
* @param The type parameter used for the return object
* @param uri The URI to call
* @param obj The object to use for the POST
* @param headers A set of headers to add to the request
* @param returnType The type to marshall the result back into
* @return The return type
* @throws IOException if there is a communication error.
*/
protected Optional executePostRequest(URI uri, Object obj, Map headers, Type returnType)
throws IOException
{
HttpPost request = new HttpPost(uri);
applyHeaders(request, headers);
request.setEntity(new StringEntity(gson.toJson(obj), ContentType.APPLICATION_JSON));
HttpResponse response = client.execute(request);
handleResponseError("POST", uri, response);
logResponse(uri, response);
return extractEntityFromResponse(response, returnType);
}
/**
* Execute a PATCH request.
* @param uri The URI to call
* @param obj The object to use for the PATCH
* @throws IOException if there is a communication error.
* @throws URISyntaxException if there is a format error in the URL.
*/
protected void executePatchRequest(URI uri, Object obj) throws IOException, URISyntaxException
{
executePatchRequest(uri, obj, null, null);
}
/**
* Execute a PATCH request.
* @param uri The URI to call
* @param obj The object to use for the PATCH
* @param headers A set of headers to add to the request
* @param queryParams A set of query parameters to add to the request
* @throws IOException if there is a communication error.
* @throws URISyntaxException if there is a format error in the URL.
*/
protected void executePatchRequest(URI uri, Object obj, Map headers, List queryParams)
throws IOException, URISyntaxException
{
URIBuilder builder = new URIBuilder(uri);
builder = applyQueryParams(builder, queryParams);
HttpPatch request = new HttpPatch(builder.build());
applyHeaders(request, headers);
request.setEntity(new StringEntity(gson.toJson(obj), ContentType.APPLICATION_JSON));
HttpResponse response = client.execute(request);
handleResponseError("PATCH", uri, response);
logResponse(uri, response);
}
/**
* Execute a PATCH request with a return object.
* @param The type parameter used for the return object
* @param uri The URI to call
* @param obj The object to use for the PATCH
* @param headers A set of headers to add to the request
* @param queryParams A set of query parameters to add to the request
* @param returnType The type to marshall the result back into
* @return The return type
* @throws IOException if there is a communication error.
* @throws URISyntaxException if there is a format error in the URL.
*/
protected Optional executePatchRequest(URI uri, Object obj, Map headers,
List queryParams, Type returnType)
throws IOException, URISyntaxException
{
URIBuilder builder = new URIBuilder(uri);
builder = applyQueryParams(builder, queryParams);
HttpPatch request = new HttpPatch(builder.build());
applyHeaders(request, headers);
request.setEntity(new StringEntity(gson.toJson(obj), ContentType.APPLICATION_JSON));
HttpResponse response = client.execute(request);
handleResponseError("PATCH", uri, response);
logResponse(uri, response);
return extractEntityFromResponse(response, returnType);
}
/**
* Execute a DELETE request.
* @param uri The URI to call
* @throws IOException if there is a communication error.
* @throws URISyntaxException if there is a format error in the URL.
*/
protected void executeDeleteRequest(URI uri) throws IOException, URISyntaxException
{
executeDeleteRequest(uri, null, null);
}
/**
* Execute a DELETE request.
* @param uri The URI to call
* @param headers A set of headers to add to the request
* @param queryParams A set of query parameters to add to the request
* @throws IOException if there is a communication error.
* @throws URISyntaxException if there is a format error in the URL.
*/
protected void executeDeleteRequest(URI uri, Map headers, List queryParams)
throws IOException, URISyntaxException
{
URIBuilder builder = new URIBuilder(uri);
builder = applyQueryParams(builder, queryParams);
HttpDelete request = new HttpDelete(builder.build());
applyHeaders(request, headers);
HttpResponse response = client.execute(request);
handleResponseError("DELETE", uri, response);
logResponse(uri, response);
}
/**
* Extract the entity from the HTTP response.
* @param The type parameter used for the return object
* @param response The HTTP response to extract the entity from
* @param returnType The type to marshall the result back into
* @return The extracted entity
* @throws IOException if there is a communication error.
*/
private Optional extractEntityFromResponse(HttpResponse response, Type returnType) throws IOException
{
int statusCode = response.getStatusLine().getStatusCode();
HttpEntity entity = response.getEntity();
if(entity != null && (statusCode == 200 || statusCode == 201))
return Optional.of(readEntity(entity, returnType));
return Optional.absent();
}
/**
* Add the given set of headers to the message.
* @param message The message to add the headers to
* @param headers The headers to add
*/
private void applyHeaders(HttpMessage message, Map headers)
{
if(headers != null)
{
for (Map.Entry e : headers.entrySet())
{
message.setHeader(e.getKey(), e.getValue());
}
}
}
/**
* Add the given set of query parameters to the given URI.
* @param builder The URI builder to add the parameters to
* @param queryParams The query parameters to add
* @return The updated builder
*/
private URIBuilder applyQueryParams(URIBuilder builder, List queryParams)
{
if(queryParams != null)
{
for(int i = 0; i < queryParams.size(); i += 2)
builder = builder.setParameter(queryParams.get(i), queryParams.get(i+1));
}
return builder;
}
/**
* Log a HTTP error response.
* @param uri The URI used for the HTTP call
* @param response The HTTP call response
*/
private void logResponse(URI uri, HttpResponse response)
{
if(logger.isLoggable(Level.FINE))
logger.fine(uri.toString()+" => "+response.getStatusLine());
if(response.getStatusLine().getStatusCode() > 300)
logger.warning(response.toString());
}
/**
* Handle HTTP error responses if {@link #throwExceptions() throwExceptions} returns true.
* @param method The HTTP method type
* @param uri The URI used for the HTTP call
* @param response The HTTP call response
*/
private void handleResponseError(String method, URI uri, HttpResponse response) throws IOException
{
int statusCode = response.getStatusLine().getStatusCode();
if(statusCode != 200 && statusCode != 201 && statusCode != 204)
{
ErrorResponse error = null;
HttpEntity entity = response.getEntity();
if(entity != null)
error = readEntity(entity, ERROR);
throw new BitlyException(method, statusCode,
response.getStatusLine().getReasonPhrase(), error);
}
}
/**
* Marshalls the given HTTP response message into an object of the given type.
* @param entity The entity to be ready
* @param returnType The type to marshall the result back into
* @param response The result object
*/
private T readEntity(HttpEntity entity, Type type) throws IOException
{
T ret;
InputStream is = null;
try
{
is = entity.getContent();
ret = gson.fromJson(new InputStreamReader(is, "UTF-8"), type);
}
finally
{
if(is != null)
is.close();
}
return ret;
}
}