org.codice.ddf.admin.sources.utils.RequestUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.codice.ddf.admin.sources.utils.RequestUtils.java

Source

/**
 * Copyright (c) Codice Foundation
 *
 * <p>This is free software: you can redistribute it and/or modify it under the terms of the GNU
 * Lesser General Public License as published by the Free Software Foundation, either version 3 of
 * the License, or any later version.
 *
 * <p>This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details. A copy of the GNU Lesser General Public
 * License is distributed along with this program and can be found at
 * <http://www.gnu.org/licenses/lgpl.html>.
 */
package org.codice.ddf.admin.sources.utils;

import static org.codice.ddf.admin.common.report.message.DefaultMessages.cannotConnectError;

import java.io.IOException;
import java.net.URL;
import java.net.URLConnection;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Map;
import javax.ws.rs.ProcessingException;
import javax.ws.rs.core.Response;
import org.apache.commons.lang3.StringUtils;
import org.apache.cxf.jaxrs.client.WebClient;
import org.codice.ddf.admin.api.report.Report;
import org.codice.ddf.admin.common.fields.common.CredentialsField;
import org.codice.ddf.admin.common.fields.common.ResponseField;
import org.codice.ddf.admin.common.fields.common.UrlField;
import org.codice.ddf.admin.common.report.Reports;
import org.codice.ddf.cxf.client.ClientFactoryFactory;
import org.codice.ddf.cxf.client.SecureCxfClientFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class RequestUtils {

    private static final Logger LOGGER = LoggerFactory.getLogger(RequestUtils.class);

    private static final int CLIENT_TIMEOUT_MILLIS = 10000;

    private final ClientFactoryFactory clientFactoryFactory;

    public RequestUtils(ClientFactoryFactory clientFactoryFactory) {
        this.clientFactoryFactory = clientFactoryFactory;
    }

    /**
     * Creates a secure CXF {@code WebClient} and sends a GET request to the URL given by the
     * clientUrl and optional queryParams.
     *
     * <p>Possible Error Codes to be returned - {@link
     * org.codice.ddf.admin.common.report.message.DefaultMessages#CANNOT_CONNECT}
     *
     * @param requestUrl url to send GET request to
     * @param creds optional credentials for basic authentication
     * @param queryParams optional query parameters
     * @return {@link Report} containing a {@link ResponseField}, or containing an {@link
     *     org.codice.ddf.admin.api.report.ErrorMessage}
     */
    public Report<ResponseField> sendGetRequest(UrlField requestUrl, CredentialsField creds,
            Map<String, Object> queryParams) {
        WebClient webClient = createWebClientBuilder(requestUrl.getValue(), creds.username(), creds.password())
                .queryParams(queryParams).build();

        return sendGetRequest(webClient, requestUrl);
    }

    /**
     * Sends a GET request with the given {@code WebClient}
     *
     * <p>Possible Error Codes to return - {@link
     * org.codice.ddf.admin.common.report.message.DefaultMessages#CANNOT_CONNECT}
     *
     * @param webClient {@code WebClient} to send a GET request with
     * @param urlField the original request url
     * @return {@link Response} of the request
     */
    public Report<ResponseField> sendGetRequest(WebClient webClient, UrlField urlField) {
        Report<ResponseField> responseResult = Reports.fromErrors(endpointIsReachable(urlField));
        if (responseResult.containsErrorMessages()) {
            return responseResult;
        }

        try {
            Response response = webClient.get();
            return Reports.from(responseFieldFromResponse(response, urlField));

        } catch (ProcessingException e) {
            return Reports.from(cannotConnectError(urlField.getPath()));
        }
    }

    /**
     * Sends a POST request to the specified url.
     *
     * <p>Possible Error Codes to be returned - {@link
     * org.codice.ddf.admin.common.report.message.DefaultMessages#CANNOT_CONNECT}
     *
     * @param urlField URL to send Post request to
     * @param creds optional credentials consisting of a username and password
     * @param contentType Mime type of the post body
     * @param content Body of the post request
     * @return a {@link Report} containing a {@link ResponseField} or an {@link
     *     org.codice.ddf.admin.api.report.ErrorMessage} on failure.
     */
    public Report<ResponseField> sendPostRequest(UrlField urlField, CredentialsField creds, String contentType,
            String content) {
        WebClient webClient = createWebClientBuilder(urlField.getValue(), creds.username(), creds.password())
                .contentType(contentType).build();

        return sendPostRequest(webClient, urlField, content);
    }

    /**
     * Sends a POST request with the given {@code WebClient}
     *
     * <p>Possible Error Codes to return - {@link
     * org.codice.ddf.admin.common.report.message.DefaultMessages#CANNOT_CONNECT}
     *
     * @param webClient {@code WebClient} to send POST request with
     * @param urlField original request url field
     * @param content Body of the post request
     * @return a {@link Report} containing a {@link ResponseField} or an {@link
     *     org.codice.ddf.admin.api.report.ErrorMessage} on failure.
     */
    public Report<ResponseField> sendPostRequest(WebClient webClient, UrlField urlField, String content) {
        Report endpointIsReachableReport = endpointIsReachable(urlField);
        if (endpointIsReachableReport.containsErrorMessages()) {
            return Reports.fromErrors(endpointIsReachable(urlField));
        }
        try {
            Response response = webClient.post(content);
            return Reports.from(responseFieldFromResponse(response, urlField));

        } catch (ProcessingException e) {
            return Reports.from(cannotConnectError(urlField.getPath()));
        }
    }

    /**
     * Attempts to open a connection to a URL.
     *
     * <p>Possible Error Codes to be returned - {@link
     * org.codice.ddf.admin.common.report.message.DefaultMessages#CANNOT_CONNECT}
     *
     * @param urlField {@link UrlField} containing the URL to connect to
     * @return a {@link Report} containing no messages on success, or containing {@link
     *     org.codice.ddf.admin.api.report.ErrorMessage}s on failure.
     */
    public Report<Void> endpointIsReachable(UrlField urlField) {
        URLConnection urlConnection = null;
        try {
            urlConnection = new URL(urlField.getValue()).openConnection();
            urlConnection.setConnectTimeout(CLIENT_TIMEOUT_MILLIS);
            urlConnection.connect();
            LOGGER.debug("Successfully reached {}.", urlField);
        } catch (IOException e) {
            LOGGER.debug("Failed to reach {}, returning an error.", urlField, e);
            return Reports.from(cannotConnectError(urlField.getPath()));
        } finally {
            try {
                if (urlConnection != null) {
                    urlConnection.getInputStream().close();
                }
            } catch (IOException e) {
                LOGGER.debug("Error closing connection stream.");
            }
        }
        return Reports.emptyReport();
    }

    public class WebClientBuilder {

        private final WebClient webClient;

        private WebClientBuilder(String url, String username, String password) {
            this(url, username, password, WebClient.class);
        }

        private WebClientBuilder(String url, String username, String password, Class clientServiceClass) {

            SecureCxfClientFactory<WebClient> clientFactory = StringUtils.isEmpty(username)
                    || StringUtils.isEmpty(password)
                            ? clientFactoryFactory.getSecureCxfClientFactory(url, clientServiceClass)
                            : clientFactoryFactory.getSecureCxfClientFactory(url, clientServiceClass, username,
                                    password);

            webClient = AccessController.doPrivileged((PrivilegedAction<WebClient>) clientFactory::getWebClient);
        }

        public WebClientBuilder queryParams(Map<String, Object> queryParams) {
            queryParams.entrySet().forEach(entry -> webClient.query(entry.getKey(), entry.getValue()));

            return this;
        }

        public WebClientBuilder path(String path) {
            webClient.path(path);
            return this;
        }

        public WebClientBuilder contentType(String contentType) {
            webClient.type(contentType);
            return this;
        }

        public WebClientBuilder accept(String... mediaTypes) {
            webClient.accept(mediaTypes);
            return this;
        }

        public WebClientBuilder encoding(String encoding) {
            webClient.encoding(encoding);
            return this;
        }

        public WebClientBuilder acceptEncoding(String... acceptEncodings) {
            webClient.acceptEncoding(acceptEncodings);
            return this;
        }

        public WebClientBuilder header(String header, Object... values) {
            webClient.header(header, values);
            return this;
        }

        public WebClientBuilder headers(Map<String, Object> headers) {
            headers.entrySet().forEach(entry -> webClient.header(entry.getKey(), entry.getValue()));

            return this;
        }

        public WebClient build() {
            return webClient;
        }
    }

    public WebClientBuilder createWebClientBuilder(String url, String username, String password) {
        return new WebClientBuilder(url, username, password);
    }

    public WebClientBuilder createWebClientBuilder(String url, String username, String password,
            Class serviceClass) {
        return new WebClientBuilder(url, username, password, serviceClass);
    }

    private ResponseField responseFieldFromResponse(Response response, UrlField requestUrl) {
        String contentType = response.getMediaType() == null ? null : response.getMediaType().toString();

        return new ResponseField().responseBody(response.readEntity(String.class)).statusCode(response.getStatus())
                .requestUrlField(requestUrl).contentType(contentType);
    }
}