no.api.meteo.client.DefaultMeteoClient.java Source code

Java tutorial

Introduction

Here is the source code for no.api.meteo.client.DefaultMeteoClient.java

Source

/*
 * Copyright (c) 2011-2015 Amedia Utvikling AS.
 *
 * 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 no.api.meteo.client;

import lombok.extern.slf4j.Slf4j;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.util.EntityUtils;

import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;

/**
 * Default Meteo Client implementation.
 *
 * This implementation is using the PoolingHttpClientConnectionManager for managing connections against the MET API.
 * It should be thread safe, but don't take the word for it until you have tested it properly in your own environment.
 */
@Slf4j
public class DefaultMeteoClient implements MeteoClient {

    private final PoolingHttpClientConnectionManager connManager;

    private RequestConfig defaultRequestConfig;

    private String metDomain = "api.met.no";

    private String userAgent;

    private int timeout = 2000;

    /**
     * Constructor for this Meteo Client implementation with max number of total connections set to 200
     */
    public DefaultMeteoClient(String userAgent) {
        this.connManager = new PoolingHttpClientConnectionManager();
        this.userAgent = userAgent;
        init(200);
    }

    /**
     * Constructor for this Meteo Client implementation asking for the maximum number of simultaneous connections
     * allowed.
     *
     * @param maxTotalConnections
     *         The number of simultaneous connections allowed.
     */
    public DefaultMeteoClient(int maxTotalConnections) {
        this.connManager = new PoolingHttpClientConnectionManager();
        init(maxTotalConnections);
    }

    @Override
    public MeteoResponse fetchContent(URI uri) throws MeteoClientException {
        log.debug("Going to fetch content from : %", uri.toString());
        CloseableHttpClient client = createClient();
        CloseableHttpResponse response = null;

        try {
            response = client.execute(prepareHttpGet(uri));
            validateResponse(response);
            return handleEntity(uri, response);
        } catch (IOException e) {
            throw new MeteoClientException("Got IOException while fetching content for: " + uri.toString(), e);
        } finally {
            closeResponse(response);
            closeClient(client);
        }
    }

    @Override
    public void setProxy(String hostname, int port) {
        defaultRequestConfig = RequestConfig.copy(defaultRequestConfig).setProxy(new HttpHost(hostname, port))
                .build();
    }

    @Override
    public void setMetDomain(String metDomain) {
        this.metDomain = metDomain;
    }

    @Override
    public String getMetDomain() {
        return metDomain;
    }

    @Override
    public void setTimeout(int timeout) {
        this.timeout = timeout;
    }

    @Override
    public void shutdown() {
        connManager.shutdown();
    }

    private void init(int maxTotalConnections) {
        connManager.setMaxTotal(maxTotalConnections);
        connManager.setDefaultMaxPerRoute(maxTotalConnections);
        defaultRequestConfig = RequestConfig.custom().setCookieSpec(CookieSpecs.IGNORE_COOKIES)
                .setExpectContinueEnabled(false).build();
    }

    private HttpGet prepareHttpGet(URI uri) {
        HttpGet get = new HttpGet(uri);
        get.setHeader("User-Agent", userAgent);
        get.setConfig(createRequestConfig());
        return get;
    }

    private void validateResponse(CloseableHttpResponse response) throws MeteoClientException {
        if (response.getStatusLine().getStatusCode() != 200 && response.getStatusLine().getStatusCode() != 203) {
            throw new MeteoClientException(
                    "The request failed with error code " + response.getStatusLine().getStatusCode() + " : "
                            + response.getStatusLine().getReasonPhrase());
        }
    }

    private MeteoResponse handleEntity(URI uri, CloseableHttpResponse response)
            throws IOException, MeteoClientException {
        HttpEntity entity = response.getEntity();

        if (entity != null) {
            return new MeteoResponse(EntityUtils.toString(entity), createMeteoResponseHeaders(response),
                    response.getStatusLine().getStatusCode(), response.getStatusLine().getReasonPhrase());
        } else {
            throw new MeteoClientException("No content returned from response for: " + uri.toString());
        }
    }

    private RequestConfig createRequestConfig() {
        return RequestConfig.copy(defaultRequestConfig).setSocketTimeout(timeout).setConnectTimeout(timeout)
                .setConnectionRequestTimeout(timeout).build();
    }

    private CloseableHttpClient createClient() {
        return HttpClients.custom().setConnectionManager(connManager).setConnectionManagerShared(true).build();
    }

    private void closeClient(CloseableHttpClient client) {
        try {
            if (client != null) {
                client.close();
            }
        } catch (IOException e) {
            log.warn("Could not close http client. This might cause trouble further down.", e);
        }
    }

    private void closeResponse(CloseableHttpResponse response) {
        try {
            if (response != null) {
                response.close();
            }
        } catch (IOException e) {
            log.warn("Could not close http response. This might cause trouble further down.", e);
        }
    }

    private List<MeteoResponseHeader> createMeteoResponseHeaders(HttpResponse response) {
        List<MeteoResponseHeader> headers = new ArrayList<>();
        for (Header header : response.getAllHeaders()) {
            log.debug("Adding response header : " + header.toString());
            headers.add(new MeteoResponseHeader(header.getName(), header.getValue()));
        }
        return headers;
    }

}