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

com.urbanairship.api.client.UrbanAirshipClient Maven / Gradle / Ivy

There is a newer version: 9.4.2
Show newest version
/*
 * Copyright (c) 2013-2016.  Urban Airship and Contributors
 */

package com.urbanairship.api.client;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import com.google.common.io.BaseEncoding;
import com.urbanairship.api.client.parse.OAuthTokenResponse;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Properties;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

/**
 * The UrbanAirshipClient class handles HTTP requests to the Urban Airship API.
 */
public class UrbanAirshipClient implements Closeable {

    private static final Logger log = LoggerFactory.getLogger(UrbanAirshipClient.class);

    private final RequestClient client;
    private final Optional baseUri;
    private final Optional useEuropeanSite;
    private final String key;
    private final Optional secret;
    private final Optional bearerToken;
    private final Optional oAuthCredentials;
    private final String userAgent;
    public static final String US_URI = "https://api.asnapius.com";
    public static final String EU_URI = "https://api.asnapieu.com";
    public static final String EU_OAUTH_URI = "https://oauth2.asnapieu.com";
    public static final String US_OAUTH_URI = "https://oauth2.asnapius.com";
    public final String oAuthBaseUri;
    private OAuthTokenResponse oAuthTokenResponse;

    private UrbanAirshipClient(Builder builder) {
        this.client = builder.client;
        this.key = builder.key;
        this.useEuropeanSite = builder.useEuropeanSite;
        this.secret = Optional.ofNullable(builder.secret);
        this.bearerToken = Optional.ofNullable(builder.bearerToken);
        this.oAuthCredentials = Optional.ofNullable(builder.oAuthCredentials);
        this.baseUri = builder.baseUri;
        this.oAuthBaseUri = builder.oAuthBaseUri;
        userAgent = getUserAgent(builder.key);
    }

    /**
     * New UrbanAirshipClient Builder.
     *
     * @return UrbanAirshipClient Builder.
     */
    public static Builder newBuilder() {
        return new Builder();
    }

    public  Future executeAsync(final Request request, ResponseCallback callback) {
        return client.executeAsync(request, callback, createHeaders(request));
    }

    public  Future executeAsync(Request request) {
        return executeAsync(request, null);
    }

    public  Response execute(Request request) throws IOException {
        return execute(request, null);
    }

    public  Response execute(Request request, ResponseCallback callback) throws IOException {
        try {
            return executeAsync(request, callback).get();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new RuntimeException("Thread interrupted while retrieving response from future", e);
        } catch (ExecutionException e) {
            throw new RuntimeException("Failed to retrieve response from future", e);
        }
    }


    private Map createHeaders(Request request) {
        Map headers = new HashMap<>();

        headers.put("User-Agent", userAgent);
        Map requestHeaders = request.getRequestHeaders();
        if (requestHeaders != null) {
            headers.putAll(requestHeaders);
        }

        String auth;

        if (request.bearerTokenAuthRequired()) {
            Preconditions.checkArgument(bearerToken.isPresent(), "Bearer token required for request: " + request);
            auth = "Bearer " + bearerToken.get();
        } else if (getAppSecret().isPresent()) {
            auth = "Basic " + BaseEncoding.base64().encode((getAppKey() + ":" + getAppSecret().get()).getBytes());
        } else if (bearerToken.isPresent() && request.canUseBearerTokenAuth()) {
            auth = "Bearer " + bearerToken.get();
        } else if (getOAuthCredentials().isPresent()) {
            ensureValidToken(oAuthBaseUri);
            auth = "Bearer " + oAuthTokenResponse.getAccessToken();
        } else {
            throw new IllegalArgumentException("No valid authentication method found for this request: " + request);
        }

        headers.put("Authorization", auth);
        headers.put("X-UA-Appkey", getAppKey());

        return headers;
    }

    /**
     * Retrieve the client user agent.
     *
     * @param appKey String
     * @return The user agent.
     */
    @VisibleForTesting
    public String getUserAgent(String appKey) {
        String userAgent = "UNKNOWN";
        InputStream stream = getClass().getResourceAsStream("/client.properties");

        if (stream != null) {
            Properties props = new Properties();
            try {
                props.load(stream);
                stream.close();
                userAgent = "UAJavaLib/" + props.get("client.version") + " " + appKey;
            } catch (IOException e) {
                log.error("Failed to retrieve client user agent due to IOException - setting to \"UNKNOWN\"", e);
            }
        }
        return userAgent;
    }

    /**
     * Close the underlying HTTP client's thread pool.
     */
    @Override
    public void close() throws IOException {
        log.info("Closing client");
        client.close();
    }

    /**
     * Get the Base URI.
     *
     * @return The base URI.
     */
    public Optional getBaseUri() {
        return baseUri;
    }

    /**
     * Get useEuropeanSite.
     *
     * @return The useEuropeanSite value.
     */
    public Optional getUseEuropeanSite() {
        return useEuropeanSite;
    }

    /**
     * Get the app key.
     * 
     * @return The app key.
     */
    public String getAppKey() {
        return key;
    }

    /**
     * Get the app secret.
     * 
     * @return The app secret.
     */
    public Optional getAppSecret() {
        return secret;
    }

    /**
     * Get the bearer token.
     * 
     * @return The bearer token.
     */
    public Optional getBearerToken() {
        return bearerToken;
    }

    /**
     * Get the OAuthCredentials.
     *
     * @return The OAuthCredentials
     */
    public Optional getOAuthCredentials() {
        return oAuthCredentials;
    }


    /**
     * Get the request client.
     * 
     * @return The RequestClient.
     */
    public RequestClient getRequestClient() {
        return client;
    }

    /**
     * UrbanAirshipClient builder.
     */
    public static class Builder {

        private String key;
        private String secret;
        private String bearerToken;
        private OAuthCredentials oAuthCredentials;
        private Optional baseUri = Optional.empty();
        private Optional useEuropeanSite = Optional.empty();
        private String oAuthBaseUri;

        private RequestClient client;

        /**
         * Set the app key.
         * 
         * @param key String app key
         * @return Builder
         */
        public Builder setKey(String key) {
            this.key = key;
            return this;
        }

        /**
         * Set useEuropeanSite.
         *
         * @param useEuropeanSite Boolean
         * @return Builder
         */
        public Builder setUseEuropeanSite(boolean useEuropeanSite) {
            this.useEuropeanSite = Optional.of(useEuropeanSite);
            return this;
        }

        /**
         * Set the app secret.
         * 
         * @param appSecret String app secret
         * @return Builder
         */
        public Builder setSecret(String appSecret) {
            this.secret = appSecret;
            return this;
        }

        /**
         * Changes base URI. Without changing URI, it defaults to
         * https://go.urbanairship.com. To send to European Servers use
         * UrbanAirshipClient.EU_URI
         * 
         * @param baseUri String baseUri used for requests
         * @return Builder
         */
        public Builder setBaseUri(String baseUri) {
            this.baseUri = Optional.of(baseUri);
            return this;
        }

        /**
         * Set the bearer token.
         * 
         * @param bearerToken String bearer token
         * @return Builder
         */
        public Builder setBearerToken(String bearerToken) {
            this.bearerToken = bearerToken;
            return this;
        }

        /**
         * Set the oAuthCredentials.
         *
         * @param oAuthCredentials String
         * @return Builder
         */
        public Builder setOAuthCredentials(OAuthCredentials oAuthCredentials) {
            this.oAuthCredentials = oAuthCredentials;
            return this;
        }

        /**
         * Set an oAuthBaseUri.
         *
         * @param oAuthBaseUri String
         * @return Builder
         */
        public Builder setOAuthBaseUri(String oAuthBaseUri) {
            this.oAuthBaseUri = oAuthBaseUri;
            return this;
        }

        /**
         * Set a custom client.
         * 
         * @param client RequestClient client
         * @return Builder
         */
        public Builder setClient(RequestClient client) {
            this.client = client;
            return this;
        }

        /**
         * Build an UrbanAirshipClient object. Will fail if any of the following
         * preconditions are not met.
         * 
         * 
         * 1. App key or client must be set.
         * 2. App secret or bearer token must be set if no client is provided.
         * 3. The base URI has been overridden but not set.
         * 4. Max for non-POST 5xx retries must be set, already defaults to 10 when using the default client.
         * 5. HTTP client config builder must be set in the default client, already defaults to a new builder.
         * 
* * @return UrbanAirshipClient */ public UrbanAirshipClient build() { Preconditions.checkNotNull(key, "App key is required to build UrbanAirshipClient"); if (secret == null && bearerToken == null && oAuthCredentials == null) { throw new NullPointerException("Secret, bearer token, or OAuth credentials must be set"); } if (!baseUri.isPresent()) { baseUri = Optional.of(useEuropeanSite.orElse(false) ? EU_URI : US_URI); } if (client == null) { client = AsyncRequestClient.newBuilder().setBaseUri(baseUri.get()).build(); } if (oAuthCredentials != null && oAuthBaseUri == null) { oAuthBaseUri = baseUri.get().equals(EU_URI) ? EU_OAUTH_URI : US_OAUTH_URI; } return new UrbanAirshipClient(this); } } private void ensureValidToken(String oAuthBaseUri) { if (oAuthCredentials.isPresent()) { synchronized (oAuthCredentials) { OAuthCredentials credentials = oAuthCredentials.get(); if (oAuthTokenResponse == null || oAuthTokenResponse.isTokenExpired()) { try { OAuthTokenFetcher tokenFetcher = new OAuthTokenFetcher(); oAuthTokenResponse = tokenFetcher.fetchToken(credentials, oAuthBaseUri); } catch (IOException e) { throw new RuntimeException("Failed to fetch OAuth access token", e); } } } } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy