c61b7a4df20b6be39ee47ea388528dc88375a44a
[dcaegen2/collectors/datafile.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * Copyright (C) 2018 NOKIA Intellectual Property, 2018-2019 Nordix Foundation. All rights reserved.
4  * ================================================================================
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * SPDX-License-Identifier: Apache-2.0
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.onap.dcaegen2.collectors.datafile.service.producer;
22
23 import java.nio.charset.StandardCharsets;
24 import java.security.KeyManagementException;
25 import java.security.KeyStoreException;
26 import java.security.NoSuchAlgorithmException;
27 import java.time.Duration;
28 import java.util.Map;
29 import java.util.concurrent.Future;
30 import javax.net.ssl.SSLContext;
31 import org.apache.commons.codec.binary.Base64;
32 import org.apache.http.HttpResponse;
33 import org.apache.http.client.config.RequestConfig;
34 import org.apache.http.client.methods.HttpUriRequest;
35 import org.apache.http.conn.ssl.NoopHostnameVerifier;
36 import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
37 import org.apache.http.ssl.SSLContextBuilder;
38 import org.onap.dcaegen2.collectors.datafile.exceptions.DatafileTaskException;
39 import org.onap.dcaegen2.collectors.datafile.http.HttpAsyncClientBuilderWrapper;
40 import org.onap.dcaegen2.collectors.datafile.web.PublishRedirectStrategy;
41 import org.onap.dcaegen2.services.sdk.rest.services.dmaap.client.config.DmaapPublisherConfiguration;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
44 import org.slf4j.MDC;
45 import org.slf4j.Marker;
46 import org.slf4j.MarkerFactory;
47 import org.springframework.web.util.DefaultUriBuilderFactory;
48 import org.springframework.web.util.UriBuilder;
49
50 /**
51  * Client used to send requests to DataRouter.
52  *
53  * @author <a href="mailto:przemyslaw.wasala@nokia.com">Przemysław Wąsala</a> on 7/4/18
54  * @author <a href="mailto:henrik.b.andersson@est.tech">Henrik Andersson</a>
55  */
56 public class DmaapProducerHttpClient {
57
58     private static final Duration DEFAULT_REQUEST_TIMEOUT = Duration.ofMinutes(2);
59     private static final Marker INVOKE = MarkerFactory.getMarker("INVOKE");
60     private static final Marker INVOKE_RETURN = MarkerFactory.getMarker("INVOKE_RETURN");
61
62     private final Logger logger = LoggerFactory.getLogger(this.getClass());
63
64     private final DmaapPublisherConfiguration configuration;
65
66     /**
67      * Constructor DmaapProducerReactiveHttpClient.
68      *
69      * @param dmaapPublisherConfiguration - DMaaP producer configuration object
70      */
71     public DmaapProducerHttpClient(DmaapPublisherConfiguration dmaapPublisherConfiguration) {
72         this.configuration = dmaapPublisherConfiguration;
73     }
74
75     /**
76      * Executes the given request and handles redirects.
77      *
78      * @param request the request to execute.
79      * @param contextMap context for logging.
80      *
81      * @return the response from the request.
82      *
83      * @throws DatafileTaskException if anything goes wrong.
84      */
85     public HttpResponse getDmaapProducerResponseWithRedirect(HttpUriRequest request, Map<String, String> contextMap)
86             throws DatafileTaskException {
87         MDC.setContextMap(contextMap);
88         try (CloseableHttpAsyncClient webClient = createWebClient(true, DEFAULT_REQUEST_TIMEOUT)) {
89             webClient.start();
90
91             logger.trace(INVOKE, "Starting to produce to DR {}", request);
92             Future<HttpResponse> future = webClient.execute(request, null);
93             HttpResponse response = future.get();
94             logger.trace(INVOKE_RETURN, "Response from DR {}", response);
95             return response;
96         } catch (Exception e) {
97             throw new DatafileTaskException("Unable to create web client.", e);
98         }
99     }
100
101     /**
102      * Executes the given request using the given timeout time.
103      *
104      * @param request the request to execute.
105      * @param requestTimeout the timeout time for the request.
106      * @param contextMap context for logging.
107      *
108      * @return the response from the request.
109      *
110      * @throws DatafileTaskException if anything goes wrong.
111      */
112     public HttpResponse getDmaapProducerResponseWithCustomTimeout(HttpUriRequest request, Duration requestTimeout,
113             Map<String, String> contextMap) throws DatafileTaskException {
114         MDC.setContextMap(contextMap);
115         try (CloseableHttpAsyncClient webClient = createWebClient(false, requestTimeout)) {
116             webClient.start();
117
118             logger.trace(INVOKE, "Starting to produce to DR {}", request);
119             Future<HttpResponse> future = webClient.execute(request, null);
120             HttpResponse response = future.get();
121             logger.trace(INVOKE_RETURN, "Response from DR {}", response);
122             return response;
123         } catch (Exception e) {
124             throw new DatafileTaskException("Unable to create web client.", e);
125         }
126     }
127
128     /**
129      * Adds the user credentials needed to talk to DataRouter to the provided request.
130      *
131      * @param request the request to add credentials to.
132      */
133     public void addUserCredentialsToHead(HttpUriRequest request) {
134         String plainCreds = configuration.dmaapUserName() + ":" + configuration.dmaapUserPassword();
135         byte[] plainCredsBytes = plainCreds.getBytes(StandardCharsets.ISO_8859_1);
136         byte[] base64CredsBytes = Base64.encodeBase64(plainCredsBytes);
137         String base64Creds = new String(base64CredsBytes);
138         logger.trace("base64Creds...: {}", base64Creds);
139         request.addHeader("Authorization", "Basic " + base64Creds);
140     }
141
142     /**
143      * Gets a <code>UriBuilder</code> containing the base URI needed talk to DataRouter. Specific parts can then be
144      * added to the URI by the user.
145      *
146      * @return a <code>UriBuilder</code> containing the base URI needed talk to DataRouter.
147      */
148     public UriBuilder getBaseUri() {
149         return new DefaultUriBuilderFactory().builder() //
150                 .scheme(configuration.dmaapProtocol()) //
151                 .host(configuration.dmaapHostName()) //
152                 .port(configuration.dmaapPortNumber());
153     }
154
155     private CloseableHttpAsyncClient createWebClient(boolean expectRedirect, Duration requestTimeout)
156             throws KeyManagementException, NoSuchAlgorithmException, KeyStoreException {
157         SSLContext sslContext =
158                 new SSLContextBuilder().loadTrustMaterial(null, (certificate, authType) -> true).build();
159
160         HttpAsyncClientBuilderWrapper clientBuilder = getHttpClientBuilder();
161         clientBuilder.setSslContext(sslContext) //
162                 .setSslHostnameVerifier(new NoopHostnameVerifier());
163
164         if (expectRedirect) {
165             clientBuilder.setRedirectStrategy(PublishRedirectStrategy.INSTANCE);
166         }
167
168         if (requestTimeout.toMillis() > 0) {
169             int millis = (int) requestTimeout.toMillis();
170             RequestConfig requestConfig = RequestConfig.custom() //
171                     .setSocketTimeout(millis) //
172                     .setConnectTimeout(millis) //
173                     .setConnectionRequestTimeout(millis) //
174                     .build();
175
176             clientBuilder.setDefaultRequestConfig(requestConfig);
177         } else {
178             logger.error("WEB client without timeout created {}", requestTimeout);
179         }
180
181         return clientBuilder.build();
182     }
183
184     HttpAsyncClientBuilderWrapper getHttpClientBuilder() {
185         return new HttpAsyncClientBuilderWrapper();
186     }
187 }