Merge "Added support for using oauth token for Kafka"
[nonrtric/plt/ranpm.git] / datafilecollector / src / main / java / org / onap / dcaegen2 / collectors / datafile / http / DfcHttpsClient.java
1 /*-
2  * ============LICENSE_START======================================================================
3  * Copyright (C) 2021 Nokia. All rights reserved.
4  * ===============================================================================================
5  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
6  * in compliance with the License. You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software distributed under the License
11  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
12  * or implied. See the License for the specific language governing permissions and limitations under
13  * the License.
14  * ============LICENSE_END========================================================================
15  */
16 package org.onap.dcaegen2.collectors.datafile.http;
17
18 import java.io.IOException;
19 import java.io.InputStream;
20 import java.net.UnknownHostException;
21 import java.nio.file.Files;
22 import java.nio.file.Path;
23 import java.nio.file.StandardCopyOption;
24
25 import javax.net.ssl.SSLHandshakeException;
26 import javax.net.ssl.SSLPeerUnverifiedException;
27
28 import org.apache.http.HttpEntity;
29 import org.apache.http.HttpResponse;
30 import org.apache.http.client.config.RequestConfig;
31 import org.apache.http.client.methods.CloseableHttpResponse;
32 import org.apache.http.client.methods.HttpGet;
33 import org.apache.http.config.SocketConfig;
34 import org.apache.http.conn.ConnectTimeoutException;
35 import org.apache.http.conn.HttpHostConnectException;
36 import org.apache.http.impl.client.CloseableHttpClient;
37 import org.apache.http.impl.client.HttpClients;
38 import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
39 import org.apache.http.util.EntityUtils;
40 import org.onap.dcaegen2.collectors.datafile.commons.FileCollectClient;
41 import org.onap.dcaegen2.collectors.datafile.commons.FileServerData;
42 import org.onap.dcaegen2.collectors.datafile.exceptions.DatafileTaskException;
43 import org.onap.dcaegen2.collectors.datafile.exceptions.NonRetryableDatafileTaskException;
44 import org.onap.dcaegen2.collectors.datafile.service.HttpUtils;
45 import org.slf4j.Logger;
46 import org.slf4j.LoggerFactory;
47
48 /**
49  * Gets file from PNF with HTTPS protocol.
50  *
51  * @author <a href="mailto:krzysztof.gajewski@nokia.com">Krzysztof Gajewski</a>
52  */
53 public class DfcHttpsClient implements FileCollectClient {
54
55     protected CloseableHttpClient httpsClient;
56
57     private static final Logger logger = LoggerFactory.getLogger(DfcHttpsClient.class);
58     private static final int FIFTEEN_SECONDS = 15 * 1000;
59
60     private final FileServerData fileServerData;
61     private final PoolingHttpClientConnectionManager connectionManager;
62
63     public DfcHttpsClient(FileServerData fileServerData, PoolingHttpClientConnectionManager connectionManager) {
64         this.fileServerData = fileServerData;
65         this.connectionManager = connectionManager;
66     }
67
68     @Override
69     public void open() {
70         logger.trace("Setting httpsClient for file download.");
71         SocketConfig socketConfig = SocketConfig.custom().setSoKeepAlive(true).build();
72
73         RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(FIFTEEN_SECONDS).build();
74
75         httpsClient = HttpClients.custom().setConnectionManager(connectionManager).setDefaultSocketConfig(socketConfig)
76             .setDefaultRequestConfig(requestConfig).build();
77
78         logger.trace("httpsClient prepared for connection.");
79     }
80
81     @Override
82     public void collectFile(String remoteFile, Path localFile) throws DatafileTaskException {
83         logger.trace("Prepare to collectFile {}", localFile);
84         HttpGet httpGet = new HttpGet(HttpUtils.prepareHttpsUri(fileServerData, remoteFile));
85
86         String authorizationContent = getAuthorizationContent();
87         if (!authorizationContent.isEmpty()) {
88             httpGet.addHeader("Authorization", authorizationContent);
89         }
90         try {
91             HttpResponse httpResponse = makeCall(httpGet);
92             processResponse(httpResponse, localFile);
93         } catch (IOException e) {
94             logger.error("marker", e);
95             throw new DatafileTaskException("Error downloading file from server. ", e);
96         }
97         logger.trace("HTTPS collectFile OK");
98     }
99
100     private String getAuthorizationContent() throws DatafileTaskException {
101         String jwtToken = HttpUtils.getJWTToken(fileServerData);
102         if (shouldUseBasicAuth(jwtToken)) {
103             return HttpUtils.basicAuthContent(this.fileServerData.userId, this.fileServerData.password);
104         }
105         return HttpUtils.jwtAuthContent(jwtToken);
106     }
107
108     private boolean shouldUseBasicAuth(String jwtToken) throws DatafileTaskException {
109         return basicAuthValidNotPresentOrThrow() && jwtToken.isEmpty();
110     }
111
112     protected boolean basicAuthValidNotPresentOrThrow() throws DatafileTaskException {
113         if (isAuthDataEmpty()) {
114             return false;
115         }
116         if (HttpUtils.isBasicAuthDataFilled(fileServerData)) {
117             return true;
118         }
119         throw new DatafileTaskException("Not sufficient basic auth data for file.");
120     }
121
122     private boolean isAuthDataEmpty() {
123         return this.fileServerData.userId.isEmpty() && this.fileServerData.password.isEmpty();
124     }
125
126     protected HttpResponse makeCall(HttpGet httpGet) throws IOException, DatafileTaskException {
127         try {
128             HttpResponse httpResponse = executeHttpClient(httpGet);
129             if (isResponseOk(httpResponse)) {
130                 return httpResponse;
131             }
132
133             EntityUtils.consume(httpResponse.getEntity());
134             if (isErrorInConnection(httpResponse)) {
135                 logger.warn("Failed to download file, reason: {}, code: {}",
136                     httpResponse.getStatusLine().getReasonPhrase(), httpResponse.getStatusLine());
137                 throw new NonRetryableDatafileTaskException(HttpUtils.retryableResponse(getResponseCode(httpResponse)));
138             }
139             throw new DatafileTaskException(HttpUtils.nonRetryableResponse(getResponseCode(httpResponse)));
140         } catch (ConnectTimeoutException | UnknownHostException | HttpHostConnectException | SSLHandshakeException
141             | SSLPeerUnverifiedException e) {
142             logger.warn("Unable to get file from xNF: {}", e.getMessage());
143             throw new NonRetryableDatafileTaskException("Unable to get file from xNF. No retry attempts will be done.",
144                 e);
145         }
146     }
147
148     protected CloseableHttpResponse executeHttpClient(HttpGet httpGet) throws IOException {
149         return httpsClient.execute(httpGet);
150     }
151
152     protected boolean isResponseOk(HttpResponse httpResponse) {
153         return getResponseCode(httpResponse) == 200;
154     }
155
156     private int getResponseCode(HttpResponse httpResponse) {
157         return httpResponse.getStatusLine().getStatusCode();
158     }
159
160     protected boolean isErrorInConnection(HttpResponse httpResponse) {
161         return getResponseCode(httpResponse) >= 400;
162     }
163
164     protected void processResponse(HttpResponse response, Path localFile) throws IOException {
165         logger.trace("Starting to process response.");
166         HttpEntity entity = response.getEntity();
167         InputStream stream = entity.getContent();
168         long numBytes = writeFile(localFile, stream);
169         stream.close();
170         EntityUtils.consume(entity);
171         logger.trace("Transmission was successful - {} bytes downloaded.", numBytes);
172     }
173
174     protected long writeFile(Path localFile, InputStream stream) throws IOException {
175         return Files.copy(stream, localFile, StandardCopyOption.REPLACE_EXISTING);
176     }
177
178     @Override
179     public void close() {
180         logger.trace("Https client has ended downloading process.");
181     }
182 }