All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.bytefish.fcmjava.client.http.apache.DefaultHttpClient Maven / Gradle / Ivy

There is a newer version: 2.5
Show newest version
// Copyright (c) Philipp Wagner. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

package de.bytefish.fcmjava.client.http.apache;

import de.bytefish.fcmjava.client.http.IHttpClient;
import de.bytefish.fcmjava.client.http.apache.utils.RetryHeaderUtils;
import de.bytefish.fcmjava.client.utils.JsonUtils;
import de.bytefish.fcmjava.client.utils.OutParameter;
import de.bytefish.fcmjava.exceptions.*;
import de.bytefish.fcmjava.http.options.IFcmClientSettings;
import org.apache.http.*;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.methods.RequestBuilder;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.time.Duration;

/**
 * This DefaultHttpClient is based on the Apache DefaultHttpClient.
 *
 * If you need to configure the Apache DefaultHttpClient (proxy settings, timeouts, ...) you can call the configure(...)
 * method to modify the HttpClientBuilder used for creating Apache DefaultHttpClient instances.
 */
public class DefaultHttpClient implements IHttpClient {

    private final IFcmClientSettings settings;
    private final HttpClientBuilder httpClientBuilder;

    public DefaultHttpClient(IFcmClientSettings settings) {
        this(settings, HttpClientBuilder.create());
    }

    public DefaultHttpClient(IFcmClientSettings settings, HttpClientBuilder httpClientBuilder) {

        if(settings == null) {
            throw new IllegalArgumentException("settings");
        }

        if(httpClientBuilder == null) {
            throw new IllegalArgumentException("httpClientBuilder");
        }

        this.settings = settings;
        this.httpClientBuilder = httpClientBuilder;
    }


    private  void internalPost(TRequestMessage requestMessage) throws IOException {

        try (CloseableHttpClient client = httpClientBuilder.build()) {

            // Execute the Request:
            try(CloseableHttpResponse response = client.execute(buildPostRequest(requestMessage))) {

                // Evaluate the Response:
                evaluateResponse(response);

                // Get the HttpEntity:
                HttpEntity entity = response.getEntity();

                // Let's be a good citizen and consume the HttpEntity:
                if(entity != null) {

                    // Make Sure it is fully consumed:
                    EntityUtils.consume(entity);
                }
            }
        }
    }

    private  TResponseMessage internalPost(TRequestMessage requestMessage, Class responseType) throws IOException {

        try(CloseableHttpClient client = httpClientBuilder.build()) {

            // Execute the Request:
            try(CloseableHttpResponse response = client.execute(buildPostRequest(requestMessage))) {

                // Evaluate the Response:
                evaluateResponse(response);

                // Get the HttpEntity of the Response:
                HttpEntity entity = response.getEntity();

                // If we don't have a HttpEntity, we won't be able to convert it:
                if(entity == null) {
                    // Simply return null (no response) in this case:
                    return null;
                }

                // Get the JSON Body:
                String responseBody = EntityUtils.toString(entity);

                // Make Sure it is fully consumed:
                EntityUtils.consume(entity);

                // And finally return the Response Message:
                return JsonUtils.getEntityFromString(responseBody, responseType);
            }
        }
    }

    private  HttpUriRequest buildPostRequest(TRequestMessage requestMessage) {

        // Get the JSON representation of the given request message:
        String content = JsonUtils.getAsJsonString(requestMessage);

        return RequestBuilder.post(settings.getFcmUrl())
                .addHeader(HttpHeaders.AUTHORIZATION, String.format("key=%s", settings.getApiKey()))
                .setHeader(HttpHeaders.CONTENT_TYPE, "application/json")
                .setEntity(new StringEntity(content, StandardCharsets.UTF_8))
                .build();
    }

    private void evaluateResponse(HttpResponse httpResponse) {

        // Early exit, if there is no HTTP Response:
        if (httpResponse == null) {
            return;
        }

        // Early exit, if we can't determine the Status:
        if (httpResponse.getStatusLine() == null) {
            return;
        }

        // Get the HTTP Status Code:
        int httpStatusCode = httpResponse.getStatusLine().getStatusCode();

        // Is it OK? So we can exit here:
        if (httpStatusCode == HttpStatus.SC_OK) {
            return;
        }

        // The Error Reason:
        String reasonPhrase = httpResponse.getStatusLine().getReasonPhrase();

        // If it is a Bad Request, we could not retry it:
        if (httpStatusCode == HttpStatus.SC_BAD_REQUEST) {
            throw new FcmBadRequestException(reasonPhrase);
        }

        // If we are unauthorized, we could not retry it:
        if (httpStatusCode == HttpStatus.SC_UNAUTHORIZED) {
            throw new FcmAuthenticationException(reasonPhrase);
        }

        // Any Status Code between 500 and 600 could be retried:
        if (httpStatusCode >= 500 && httpStatusCode < 600) {

            // Holds the Duration, which has been sent by the Server:
            OutParameter result = new OutParameter<>();

            // Try to determine the next interval we can send at:
            if (RetryHeaderUtils.tryDetermineRetryDelay(httpResponse, result)) {
                throw new FcmRetryAfterException(result.get(), reasonPhrase);
            }
        }

        throw new FcmGeneralException(reasonPhrase);
    }

    @Override
    public  void post(TRequestMessage requestMessage) {
        try {
            internalPost(requestMessage);
        } catch (IOException e) {
            throw new FcmCommunicationException("Error making POST Request", e);
        }
    }

    @Override
    public  TResponseMessage post(TRequestMessage requestMessage, Class responseType) {
        try {
            return internalPost(requestMessage, responseType);
        } catch (IOException e) {
            throw new FcmCommunicationException("Error making POST Request", e);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy