Bugfix
[nonrtric.git] / policy-agent / src / main / java / org / oransc / policyagent / clients / AsyncRestClient.java
1 /*-
2  * ========================LICENSE_START=================================
3  * O-RAN-SC
4  * %%
5  * Copyright (C) 2019 Nordix Foundation
6  * %%
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ========================LICENSE_END===================================
19  */
20
21 package org.oransc.policyagent.clients;
22
23 import io.netty.channel.ChannelOption;
24 import io.netty.handler.timeout.ReadTimeoutHandler;
25 import io.netty.handler.timeout.WriteTimeoutHandler;
26
27 import java.lang.invoke.MethodHandles;
28
29 import org.slf4j.Logger;
30 import org.slf4j.LoggerFactory;
31 import org.springframework.http.MediaType;
32 import org.springframework.http.ResponseEntity;
33 import org.springframework.http.client.reactive.ReactorClientHttpConnector;
34 import org.springframework.lang.Nullable;
35 import org.springframework.web.reactive.function.client.WebClient;
36 import org.springframework.web.reactive.function.client.WebClient.RequestHeadersSpec;
37 import org.springframework.web.reactive.function.client.WebClientResponseException;
38
39 import reactor.core.publisher.Mono;
40 import reactor.netty.http.client.HttpClient;
41 import reactor.netty.tcp.TcpClient;
42
43 /**
44  * Generic reactive REST client.
45  */
46 public class AsyncRestClient {
47     private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
48     private final WebClient client;
49     private final String baseUrl;
50
51     public AsyncRestClient(String baseUrl) {
52
53         TcpClient tcpClient = TcpClient.create() //
54             .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10_000) //
55             .doOnConnected(connection -> {
56                 connection.addHandler(new ReadTimeoutHandler(10));
57                 connection.addHandler(new WriteTimeoutHandler(30));
58             });
59         HttpClient httpClient = HttpClient.from(tcpClient);
60         ReactorClientHttpConnector connector = new ReactorClientHttpConnector(httpClient);
61
62         this.client = WebClient.builder() //
63             .clientConnector(connector) //
64             .baseUrl(baseUrl) //
65             .build();
66
67         this.baseUrl = baseUrl;
68     }
69
70     public Mono<ResponseEntity<String>> postForEntity(String uri, @Nullable String body) {
71         logger.debug("POST uri = '{}{}''", baseUrl, uri);
72         Mono<String> bodyProducer = body != null ? Mono.just(body) : Mono.empty();
73         RequestHeadersSpec<?> request = client.post() //
74             .uri(uri) //
75             .contentType(MediaType.APPLICATION_JSON) //
76             .body(bodyProducer, String.class);
77         return retrieve(request);
78     }
79
80     public Mono<String> post(String uri, @Nullable String body) {
81         return postForEntity(uri, body) //
82             .flatMap(this::toBody);
83     }
84
85     public Mono<String> postWithAuthHeader(String uri, String body, String username, String password) {
86         logger.debug("POST (auth) uri = '{}{}''", baseUrl, uri);
87         RequestHeadersSpec<?> request = client.post() //
88             .uri(uri) //
89             .headers(headers -> headers.setBasicAuth(username, password)) //
90             .contentType(MediaType.APPLICATION_JSON) //
91             .bodyValue(body);
92         return retrieve(request) //
93             .flatMap(this::toBody);
94     }
95
96     public Mono<ResponseEntity<String>> putForEntity(String uri, String body) {
97         logger.debug("PUT uri = '{}{}''", baseUrl, uri);
98         RequestHeadersSpec<?> request = client.put() //
99             .uri(uri) //
100             .contentType(MediaType.APPLICATION_JSON) //
101             .bodyValue(body);
102         return retrieve(request);
103     }
104
105     public Mono<ResponseEntity<String>> putForEntity(String uri) {
106         logger.debug("PUT uri = '{}{}''", baseUrl, uri);
107         RequestHeadersSpec<?> request = client.put() //
108             .uri(uri);
109         return retrieve(request);
110     }
111
112     public Mono<String> put(String uri, String body) {
113         return putForEntity(uri, body) //
114             .flatMap(this::toBody);
115     }
116
117     public Mono<ResponseEntity<String>> getForEntity(String uri) {
118         logger.debug("GET uri = '{}{}''", baseUrl, uri);
119         RequestHeadersSpec<?> request = client.get().uri(uri);
120         return retrieve(request);
121     }
122
123     public Mono<String> get(String uri) {
124         return getForEntity(uri) //
125             .flatMap(this::toBody);
126     }
127
128     public Mono<ResponseEntity<String>> deleteForEntity(String uri) {
129         logger.debug("DELETE uri = '{}{}''", baseUrl, uri);
130         RequestHeadersSpec<?> request = client.delete().uri(uri);
131         return retrieve(request);
132     }
133
134     public Mono<String> delete(String uri) {
135         return deleteForEntity(uri) //
136             .flatMap(this::toBody);
137     }
138
139     private Mono<ResponseEntity<String>> retrieve(RequestHeadersSpec<?> request) {
140         return request.retrieve() //
141             .toEntity(String.class) //
142             .doOnError(this::onHttpError);
143     }
144
145     private void onHttpError(Throwable t) {
146         if (t instanceof WebClientResponseException) {
147             WebClientResponseException exception = (WebClientResponseException) t;
148             logger.debug("HTTP error status = '{}', body '{}'", exception.getStatusCode(),
149                 exception.getResponseBodyAsString());
150         } else {
151             logger.debug("HTTP error: {}", t.getMessage());
152         }
153     }
154
155     private Mono<String> toBody(ResponseEntity<String> entity) {
156         if (entity.getBody() == null) {
157             return Mono.just("");
158         } else {
159             return Mono.just(entity.getBody());
160         }
161     }
162
163 }